Java 为XStream中非XML格式的字段设置默认值
是否有方法创建转换器或在每次转换后执行的某些操作?对于上下文,我尝试填充不在XML中的字段的默认值,以便在数据模型更改时保持向后兼容性。例如,如果我有这个对象:Java 为XStream中非XML格式的字段设置默认值,java,import,xstream,Java,Import,Xstream,是否有方法创建转换器或在每次转换后执行的某些操作?对于上下文,我尝试填充不在XML中的字段的默认值,以便在数据模型更改时保持向后兼容性。例如,如果我有这个对象: class A { private String b; private String c; private String d; } 我的XML是这样的: <a> <b>b</b> <d>d</d> </a> 似乎唯一建议的解决方案是
class A {
private String b;
private String c;
private String d;
}
我的XML是这样的:
<a>
<b>b</b>
<d>d</d>
</a>
似乎唯一建议的解决方案是使用readResolve()
,我已经说过这不是一个有效的解决方案。您需要一个转换器
以下是您案例的代码示例:
public class AConverter implements Converter {
@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
A a = new A();
String bValue = "b";
String cValue = "c";
String dValue = "d";
while (reader.hasMoreChildren()) {
reader.moveDown();
if ("b".equals(reader.getNodeName())) {
bValue = reader.getValue();
} else if ("c".equals(reader.getNodeName())) {
cValue = reader.getValue();
} else if ("d".equals(reader.getNodeName())) {
dValue = reader.getValue();
}
reader.moveUp();
}
a.setB(bValue);
a.setC(cValue);
a.setD(dValue);
return a;
}
@Override
public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) {
A a = (A) object;
writer.startNode("b");
writer.setValue(a.getB());
writer.endNode();
writer.startNode("c");
writer.setValue(a.getC());
writer.endNode();
writer.startNode("d");
writer.setValue(a.getD());
writer.endNode();
}
@Override
public boolean canConvert(Class clazz) {
return clazz == A.class;
}
}
不要忘记注册转换器:
XStream xs = new XStream();
xs.registerConverter(new AConverter());
编辑:修复了转换器代码。c
将在XML没有为c
设置任何值时设置为null
。然后可以在getter中检查null
,并返回相应的默认值。使用
然后像往常一样用默认值初始化对象。通过字段初始化或构造函数代码(初始值设定项)
背景
如果不指定xstream,请尝试查找最佳反射提供程序。但是xstream的最佳ReflectionProvider
可能并不适合您,因为它通常选择Sun14ReflectionProvider
使用与java序列化机制相同的实例化策略,这意味着它跳过了构造函数代码,或者更准确地说,跳过了对象初始化器代码
因此,实例字段初始化如下
class A {
private String b = "DEFAULT";
}
不会应用,也不会应用构造函数代码,例如
class A {
private String b;
public A(){
b = "DEFAULT";
}
}
相反,PureJavaReflectionProvider
使用(顾名思义)java反射API来实例化对象,例如,因此执行对象初始化代码。感谢pablosaraiva,但这只对某些类A显式有效。我需要它在完整对象图中的任何对象上通用。因此它必须适用于B/C/D对象,以及B/C/D可能具有的任何对象。此外,如果在这种情况下添加了其他字段,则需要维护此转换器。理想情况下,每当我需要添加一个新的默认值时,我可以说一些类似于newDefaultField(classWithNewDefault.class,newFieldName,newDefaultValue)的话。这只是玩具问题的玩具解决方案。您可能需要一个到每个具有默认值的类的转换器。您不需要在解组时手动构造对象,您可以有一个工厂来处理它。我希望有帮助,对。我想目标是避免任何可能很快变得复杂和失控的实际维护。不幸的是,我不认为XStream提供了一个更好的解决方案,除了每个转换器或每个地方都有一个readResolve()。这是一个合适的选项,可以为使用fromXML(…)
时XML中缺少标记的成员设置默认值;特别是当默认行为只影响某个特定类的某些标记/成员时。这种方法不起作用。甚至PureJavaReflectionProvider也将默认值设置为Null这似乎不适用于具有默认值构造函数的类的Scala,即类a(字符串b=“”)您说过“readResolve将使用默认值覆盖字段,即使它实际上包含在XML中”。您可以编写readResolve()
方法来处理这种情况if(c==null){c=“c”}
我经常使用这样的代码,而且效果很好。
class A {
private String b;
public A(){
b = "DEFAULT";
}
}