使用 XStream 1.4.10 ,我正在尝试实现一个自定义转换器来处理多态。为此,我实施了一个小型测试程序。除未设置派生类型的属性外,解组工作按预期进行。我在调试器上花费了很多时间,似乎在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]
此外,如果我向该人添加大象,则会出现一个例外,即属性必须位于开始标记上,但这是另一个问题。