Question Personnalisation de la sérialisation des collections Java à l'aide de xstream


J'ai un objet qui doit être sérialisé en XML, qui contient le champ suivant:

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

XStream le sérialise très bien (après quelques alias) comme ceci:

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

Ça va, mais je voudrais pouvoir renommer le <string> éléments à, disons, <tag>. Je ne vois pas de moyen évident de le faire à partir de la documentation sur les alias sur le site XStream. Est-ce que je manque quelque chose d'évident?


11
2017-11-24 16:24


origine


Réponses:


Je suggère de changer le List<String> à un List<Tag>, où Tag est un objet de domaine qui contient essentiellement une chaîne. Alors vous dites:

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

et vous obtenez exactement ce que vous voulez. Cela évite d'avoir à rouler votre propre convertisseur.


5
2017-11-24 17:35



Par intérêt, j'ai essayé de le faire sans écrire mon propre convertisseur. Fondamentalement, je viens d'enregistrer une version spéciale instruite de CollectionConverter pour un certain champ dans une certaine classe.

Extrait pertinent:

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

Exemple à part entière:

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

Non testé mais cela devrait fonctionner. Non?

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

12
2017-11-24 16:31



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

résultat xml:

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

2
2018-02-23 02:32



Ajouter un alias pour le java.util.String classe. D'accord, cela peut casser quelque chose d'autre ailleurs, mais dans ce cas précis, cela devrait suffire.

Si vous ne voulez pas faire la chose ci-dessus, vous pouvez créer vos propres convertisseurs (voir ce tutoriel pratique) qui vous aidera à atteindre votre objectif. Et n'ayez pas peur de faire votre propre convertisseur non plus, ils sont vraiment faciles à mettre en œuvre.


1
2017-11-24 16:30



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

et dans 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
2017-10-01 14:21



pour moi travaille avec le code ci-dessous, en utilisant des chaînes:

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>

0
2017-07-02 15:14