Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

customising serialisation of java collections using xstream

I have an object that needs to be serialised as XML, which contains the following field:

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

XStream serialises it just fine (after some aliases) like this:

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

That's OK as far as it goes, but I'd like to be able to rename the <string> elements to, say, <tag>. I can't see an obvious way to do that from the alias documentation on the XStream site. Am I missing something obvious?

like image 490
Will Goring Avatar asked Nov 24 '09 16:11

Will Goring


4 Answers

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);
like image 148
jitter Avatar answered Nov 04 '22 00:11

jitter


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.

like image 40
Jim Ferrans Avatar answered Nov 04 '22 01:11

Jim Ferrans


@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>
like image 27
xjma86 Avatar answered Nov 04 '22 00:11

xjma86


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.

like image 1
Esko Avatar answered Nov 04 '22 01:11

Esko