Настройка сериализации java-коллекций с использованием xstream

У меня есть объект, который должен быть сериализован как XML, который содержит следующее поле:

List<String> tags = new List<String>();

XStream сериализует его просто отлично (после некоторых псевдонимов):

<tags>
  <string>tagOne</string>
  <string>tagTwo</string>
  <string>tagThree</string>
  <string>tagFour</string>
</tags>

Это нормально, насколько это возможно, но я хотел бы иметь возможность переименовать элементы <string>, например, <tag>. Я не вижу очевидного способа сделать это из документации псевдонима на сайте XStream. Мне что-то не хватает?

Ответ 1

Я бы предложил изменить List<String> на List<Tag>, где Tag - объект домена, который по существу просто содержит строку. Затем вы говорите:

xstream.alias("tag", org.goring.Tag.class);

и вы получите именно то, что хотите. Это позволяет избежать необходимости конвертировать собственный конвертер.

Ответ 2

Из интереса я попробовал это сделать, не написав свой собственный конвертер. В основном я просто зарегистрирую специальную командную версию CollectionConverter для определенного поля в определенном классе.

Соответствующий фрагмент:

ClassAliasingMapper mapper = new ClassAliasingMapper(xstream.getMapper());
mapper.addClassAlias("tag", String.class);
xstream.registerLocalConverter(
    Test.class,
    "tags",
    new CollectionConverter(mapper)
);

Полномасштабный пример:

import com.thoughtworks.xstream.*;
import com.thoughtworks.xstream.converters.collections.*;
import com.thoughtworks.xstream.mapper.*;
import java.util.*;

public class Test {
    public List<String> tags = new ArrayList<String>();
    public List<String> notags = new ArrayList<String>();
    public Test(String tag, String tag2) {
        tags.add(tag); tags.add(tag2);
        notags.add(tag); notags.add(tag2);
    }
    public static void main(String[] args) {
        Test test = new Test("foo", "bar");
        XStream xstream = new XStream();

        ClassAliasingMapper mapper = new ClassAliasingMapper(xstream.getMapper());
        mapper.addClassAlias("tag", String.class);
        xstream.registerLocalConverter(
            Test.class,
            "tags",
            new CollectionConverter(mapper)
        );

        System.out.println(xstream.toXML(test));
    }
}

Не проверено, но это должно сработать. Нет?

xstream.alias("tag", java.lang.String.class);

Ответ 3

@XStreamAlias("example")
public class A {
    private B myList;

    public A(){
        this.myList = new B();
    }

    public A clone(){
        A a = new A();
        a.myList = this.myList;
        return a;
    }

    public B getMyList() {
        return myList;
    }

    public void setMyList(B myList) {
        this.myList = myList;
    }   
}

public class B {
    @XStreamImplicit(itemFieldName = "myField")
    ArrayList<String> myFieldlist;

    public B(){
        this.myFieldlist = new ArrayList<String>();
    }

    public B clone(){
        B b = new B();
        b.myFieldlist = this.myFieldlist;
        return b;
    }

    public ArrayList<String> getMyFieldlist() {
            return myFieldlist;
    }

    public void setMyFieldlist(ArrayList<String> myFieldlist) {
        this.myFieldlist = myFieldlist;
    }
}


public class Test {
    public static void main(String[] args) {
        A a = new A();
        a.getMyList().getMyFieldlist().add("aa");
        a.getMyList().getMyFieldlist().add("bb");       

        XStream xs = new XStream(new DomDriver());  
        xs.processAnnotations(A.class);
        xs.processAnnotations(B.class);     

        System.out.println(xs.toXML(a));                
    }
}

xml result:

<example>
  <myList>
    <myField>aa</myField>
    <myField>bb</myField>
  </myList>
</example>

Ответ 4

Добавить псевдоним для класса java.util.String. Хорошо, это может сломать что-то еще в другом месте, но в этом конкретном случае этого должно быть достаточно.

Если вы не хотите делать что-то выше, вы можете сделать свои собственные конвертеры (см. этот удобный учебник), который поможет вы достигаете своей цели. И не бойтесь создавать свой собственный конвертер, их действительно легко реализовать.

Ответ 5

@XStreamConverter(value=ListToStringXStreamConverter.class, strings={"tag"})
List<String> tags = new List<String>();

и в ListToStringXStreamConverter.java

public class ListToStringXStreamConverter implements Converter {

private String alias;

public ListToStringXStreamConverter(String alias) {
    super();
    this.alias = alias;
}

@SuppressWarnings("rawtypes")
@Override
public boolean canConvert(Class type) {
    return true;
}

@Override
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {

    @SuppressWarnings("unchecked")
    List<String> list = (List<String>)source;

    for (String string : list) {
        writer.startNode(alias);
        writer.setValue(string);
        writer.endNode();
    }

}

@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
    throw new UnsupportedOperationException("ListToStringXStreamConverter does not offer suport for unmarshal operation");
}

}

Ответ 6

для меня работает с кодом ниже, используя строки:

xStream.alias("myTag", Person.class);
xStream.addImplicitCollection(Person.class, "myTag", "myTag", String.class);
public class Person{
    private ArrayList<String> myTag;
    // ...
}
<Person>
      <myTag>atrcxb2102</myTag>
      <myTag>sub3</myTag>
</Person>