framework - ejercicios resueltos de colecciones en java
personalización de la serialización de colecciones Java utilizando xstream (6)
Agregue un alias para la clase java.util.String
. Está bien, eso puede romper algo más en otro lugar pero en este caso exacto eso debería ser suficiente.
Si no desea hacer lo anterior, puede hacer sus propios convertidores ( consulte este útil tutorial ) que lo ayudarán a lograr su objetivo. Y no tengas miedo de crear tu propio convertidor, son realmente fáciles de implementar.
Tengo un objeto que debe ser serializado como XML, que contiene el siguiente campo:
List<String> tags = new List<String>();
XStream lo serializa bien (después de algunos alias) como este:
<tags>
<string>tagOne</string>
<string>tagTwo</string>
<string>tagThree</string>
<string>tagFour</string>
</tags>
Está bien hasta donde sea posible, pero me gustaría poder cambiar el nombre de los elementos <string>
a, digamos, <tag>
. No veo una manera obvia de hacerlo desde la documentación del alias en el sitio de XStream. ¿Me estoy perdiendo algo obvio?
Fuera de interés lo intenté sin escribir mi propio convertidor. Básicamente acabo de registrar una versión especial instruida de CollectionConverter
para cierto campo en cierta clase.
Fragmento relevante:
ClassAliasingMapper mapper = new ClassAliasingMapper(xstream.getMapper());
mapper.addClassAlias("tag", String.class);
xstream.registerLocalConverter(
Test.class,
"tags",
new CollectionConverter(mapper)
);
Ejemplo en toda regla:
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));
}
}
No probado, pero esto debería funcionar. ¿No?
xstream.alias("tag", java.lang.String.class);
Sugeriría cambiar la List<String>
a una List<Tag>
, donde la Etiqueta es un objeto de dominio que esencialmente solo contiene una Cadena. Entonces dices:
xstream.alias("tag", org.goring.Tag.class);
y obtienes exactamente lo que quieres. Esto evita tener que hacer rodar su propio convertidor.
@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));
}
}
resultado xml:
<example>
<myList>
<myField>aa</myField>
<myField>bb</myField>
</myList>
</example>
@XStreamConverter(value=ListToStringXStreamConverter.class, strings={"tag"})
List<String> tags = new List<String>();
y en 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");
}
}
para mí funciona con el siguiente código, usando cadenas:
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>