customising serialisation of java collections using xstream

佐手、 提交于 2019-11-30 18:45:19

I'd suggest changing the List<String> to a List<Tag>, where Tag is a domain object that essentially just contains a String. Then you say:

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

and you get exactly what you want. This avoids having to roll your own Converter.

Out of interest I gave it a try to do it without writing my own converter. Basically I just register a special instructed version of CollectionConverter for a certain field in a certain class.

Relevant snippet:

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

Full-blown example:

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));
    }
}

Not tested but this should work. No?

xstream.alias("tag", java.lang.String.class);
@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>

Add alias for the java.util.String class. Okay, that may break something else elsewhere but in this exact case that should be enough.

If you don't want to do the thing above, you can make your own converters (see this handy tutorial) which will help you achieve your goal. And don't be afraid of making your own converter either, they're really easy to implement.

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

and in 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");
}

}
Luciano Santos

for me works with the code below, using Strings:

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>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!