Используя XStream 1.4.10 , я пытаюсь реализовать собственный конвертер для обработки полиморфизма.Для этого я реализовал небольшую тестовую программу.Unmarshalling работает должным образом, за исключением того, что атрибуты для производных типов не установлены.Я провел много времени в отладчике, и кажется, что глубоко в context.convertAnother()
он думает, что видел стартовый тег, и выбрасывает атрибуты!
Sample XML
<person>
<name>Steve</name>
<fubar>33</fubar>
<cat stray="false" sheds="a lot" >
<name>Gypsy</name>
<nobble>nob</nobble>
</cat>
</person>
Классы доменов
@XStreamAlias("person")
public class Person {
public String name ;
public int fubar ;
@XStreamAsAttribute
public int bar ;
public Pet pet ;
public Elephant elephant ;
@Override
public String toString() {
return "Person [name=" + this.name + ", fubar=" + this.fubar + ", bar=" + this.bar + ", pet=" + this.pet + ", " + this.elephant + "]";
}
}
class Pet
{
public String name ;
}
@XStreamAlias("dog")
class Dog extends Pet
{
String breed ;
@Override
public String toString() {
return "Dog [breed=" + this.breed + ", name=" + this.name + "]";
}
}
@XStreamAlias("cat")
class Cat extends Pet
{
@XStreamAsAttribute
@XStreamAlias("stray")
Boolean stray ;
@XStreamAsAttribute
@XStreamAlias("sheds")
String sheds ;
String nobble ;
@Override
public String toString() {
return "Cat [stray=" + this.stray + ", name=" + this.name + ", nobble=" + this.nobble + ", sheds=" + this.sheds + "]";
}
}
Конвертер (сортировка не реализована!)
public class CustomConverter implements Converter {
private List<Field> fields ;
public CustomConverter()
{
this.fields = new ArrayList<>() ;
for (final Field field : Person.class.getFields()) {
if ((field.getModifiers() & Modifier.TRANSIENT) == 0) {
field.setAccessible(true);
this.fields.add(field) ;
}
}
}
@Override
public void marshal(Object source, HierarchicalStreamWriter writer,
MarshallingContext context) {
}
protected boolean setField(UnmarshallingContext context, Person person, String node, String value)
{
for (final Field field : this.fields) {
if (field.getName().equals(node)) {
try {
if (field.getType() == Integer.TYPE) {
field.set(person, Integer.valueOf(value));
}
else if (field.getType() == String.class) {
field.set(person, value) ;
}
else { // try an object
final Object valueObject = context.convertAnother(person, field.getType()) ;
field.set(person, valueObject);
}
System.out.println("set "+ node);
return true ;
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
System.err.println("can't set " + node);
return false ;
}
}
}
return false ;
}
@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
final Person person = new Person() ;
while (reader.hasMoreChildren()) {
reader.moveDown();
final String node = reader.getNodeName() ;
if (!setField(context, person, node, reader.getValue())) {
if ("cat".equals(node)) {
person.pet = (Pet) context.convertAnother(person, Cat.class);
}
else if ("dog".equals(node)){
person.pet = (Pet) context.convertAnother(context.currentObject(), Dog.class);
}
}
reader.moveUp();
}
return person ;
}
@Override
public boolean canConvert(Class type) {
return type.equals(Person.class);
}
}
Результаты (Атрибуты кошки (stray, sheds)
: null
.
set name
set fubar
Person [name=Steve, fubar=33, bar=0, pet=Cat [stray=null, name=Gypsy, nobble=nob, sheds=null], null]
Кроме того, если я добавлю слонадля человека я получаю исключение, что атрибуты должны быть в начальном теге, но это другой вопрос.