2009-11-24 6 views
11

Ich habe ein Objekt, das als XML serialisiert werden muss, die das folgende Feld enthält:Customizing Serialisierung von Java-Sammlungen mit xstream

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

XStream serialisiert es ganz gut (nach einigen Aliasnamen) wie folgt aus:

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

das OK ist so weit wie es geht, aber ich möchte in der Lage sein, die <string> Elemente zu benennen, sagen wir, <tag>. Ich kann keinen offensichtlichen Weg aus der Alias-Dokumentation auf der XStream-Site sehen. Fehle ich etwas Offensichtliches?

Antwort

5

Ich würde vorschlagen, die List<String> zu einem List<Tag> zu ändern, in dem Tag ein Domain-Objekt ist, das im Wesentlichen nur einen String enthält. Dann sagst du:

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

und du bekommst genau was du willst. Dies verhindert, dass Sie Ihren eigenen Converter rollen müssen.

+0

Genau das habe ich vor etwa einer halben Stunde gemacht. Arbeitete eine Belohnung. :) –

+2

Könnten Sie bitte erläutern, wie die Tag-Klasse sein könnte? Wenn ich eine String-Variable (sagen wir TagValue) darin zu halten, bekomme ich so etwas wie tagOne tagTwo. Danke im Voraus. – Jonna

+1

Wie Jonna oben sagt, glaube ich nicht, dass dies die gewünschte Ausgabe liefert, es sei denn, ich verpasse etwas. Ich habe es gerade ausprobiert und dasselbe gefunden wie Jonna. Die folgende Lösung, die den CollectionConverter und den ClassAliasingMapper verwendet, hat das getan, was ich in nur 3 Codezeilen benötigt habe. – DaveyDaveDave

1

Fügen Sie Alias ​​für die Klasse java.util.String hinzu. Okay, das könnte etwas anderes kaputt machen, aber in diesem Fall sollte das ausreichen.

Wenn Sie das oben genannte nicht tun möchten, können Sie Ihre eigenen Konverter (see this handy tutorial) machen, die Ihnen helfen, Ihr Ziel zu erreichen. Und haben Sie keine Angst, einen eigenen Konverter zu bauen, sie sind wirklich einfach zu implementieren.

+0

Gotcha. Ich hatte gehofft zu vermeiden, meinen eigenen Konverter zu schreiben, da die fragliche Klasse eine Tonne Felder hat, aber wenn das ist, was ich tun muss ... Danke.:) –

12

Aus Interesse habe ich es versucht, ohne meinen eigenen Konverter zu schreiben. Grundsätzlich registriere ich nur eine speziell angewiesene Version von CollectionConverter für ein bestimmtes Feld in einer bestimmten Klasse.

Relevante Schnipsel:

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

Vollgeblasenen Beispiel:

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

Nicht getestet, aber das sollte funktionieren. Nein?

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

Es funktioniert (Ich habe es gerade versucht,), aber es nimmt und Aliase die Mitglieder aller andere Sammlung von Strings in der Klasse als auch. Leider gibt es in meiner realen Klasse (anders als im Beispiel) mehr als eine solche Sammlung. –

+0

Diese Lösung funktioniert perfekt. Getestet auf XStream 1.3.1. Will> Wie ist es möglich? Diese Art von Aliasing wird nur für die Feld- "Tags" der Test-Klasse ausgeführt und jede andere Sammlung in der Test-Klasse wird durch die Standardeinstellungen von XStream-Mappern mit Alias ​​versehen (dh sie haben die gleiche XML-Repräsentation wie Sie in Ihrem ursprünglichen Post schreiben ->). ..). –

+0

Will Gorings Kommentar bezieht sich auf die erste Version meiner Antwort. Was ist der oneliner unter der Horizontalen? – jitter

2
@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 Ergebnis:

<example> 
    <myList> 
    <myField>aa</myField> 
    <myField>bb</myField> 
    </myList> 
</example> 
0
@XStreamConverter(value=ListToStringXStreamConverter.class, strings={"tag"}) 
List<String> tags = new List<String>(); 

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

} 
0

für mich unten mit dem Code funktioniert, mit 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>