前提
以下全部内容基于xstream-1.4.11.1.jar
描述
XStream在读取xml解析enum类型的信息时,默认使用的EnumConverter(com.thoughtworks.xstream.converters.enums.EnumConverter)。对于enum的支持采用的是Enum.valueOf()和enum.name()来与目标值进行匹配的,如下为源码截图:
由于这种设计是通用标准设计,所以对于一些特殊小需求就不能使用了,比如使用enum的code(int类型)值来代表enum,它就不能映射了。
因此,我们可以自定义一个转换器。
这里实践了一个可以依据enum的所有属性来映射。
实现
实现可用属性映射enum的功能
比如,我的enum有两个属性:value(string), code(int)。
public enum JfqqqEnum {
ENUM1(1,"jfqqq1"),ENUM2(2,"jfqqq2");
private String value;
private Integer code;
JfqqqEnum(Integer code,String value) {
this.code = code;
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
自定义converter
定义自己的converter,实现依据属性值进行转换。
实现方式是,我们创建自己的converter类,实现Converter接口,然后先把源代码中的EnumConverter的实现方式复制过来,然后在unmarshal函数中的解析部分换为自己的逻辑:
public class MyEnumConvertor implements Converter {
public static MyEnumConvertor getInstance() {
return new MyEnumConvertor();
}
@Override
public boolean canConvert(Class type) {
return type != null && type.isEnum() || Enum.class.isAssignableFrom(type);
}
@Override
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
writer.setValue(((Enum)source).name());
}
@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
Class type = context.getRequiredType();
if (type.getSuperclass() != Enum.class) {
type = type.getSuperclass();
}
String name = reader.getValue();
//自己的逻辑
Enum c = getByFieldValue(name, type);
if (c != null) {
return c;
}
return null;
}
private Enum getByFieldValue(String name, Class type) {
try {
Field[] declaredFields = type.getDeclaredFields();
Enum[] var6 = (Enum[])((Enum[])type.getEnumConstants());
int var7 = var6.length;
for(int var8 = 0; var8 < var7; ++var8) {
Enum c = var6[var8];
for (Field field : declaredFields) {
field.setAccessible(true);
Object o = field.get(c);
if (o.toString().equalsIgnoreCase(name)) {
return c;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
重点在getByFieldValue函数上。利用反射找到Enum的属性,然后获取其值进行比对,找到符合的就返回。
注册
最后,不要忘了,需要在XStream上注册一下,xstream才能使用我们自己的converter(值展示了关键的注册那一行代码):
xstream.registerConverter(MyEnumConvertor.getInstance());
实验
使用enum名测试通过:
<?xml version="1.0" ?>
<test>
<jfqqqEnum>ENUM1</jfqqqEnum>
</test>
使用value测试通过:
<?xml version="1.0" ?>
<test>
<jfqqqEnum>jfqqq1</jfqqqEnum>
</test>
使用code测试通过:
<?xml version="1.0" ?>
<test>
<jfqqqEnum>2</jfqqqEnum>
</test>