XStream Converter Context convertAnother теряет атрибуты - PullRequest
0 голосов
/ 28 сентября 2018

Используя 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]

Кроме того, если я добавлю слонадля человека я получаю исключение, что атрибуты должны быть в начальном теге, но это другой вопрос.

...