为enum自定义Xstream/JSON转换器



我有以下Enum:

public enum MyState {
    Open("opened"),
    Close("closed"),
    Indeterminate("unknown");
    private String desc;
    private MyState(String desc) {
        setDesc(desc);
    }
    public String getDesc() {
        return this.desc;
    }
    private void setDesc(String desc) {
        this.desc = desc;
    }
}

我正试图写一个XStream Converter,它将知道映射回JSON元素"mystate"到MyState实例。

"someJson": {
    "object1": {
        "mystate": closed
    }
}

这会在其他对象(someJsonobject1)中产生一个MyState.Close实例。我已经开始了Converter,但还没有走得很远:

public class MyStateEnumConverter implement Converter {
    @Override
    public boolean canConvert(Class clazz) {
        return clazz.equals(MyState.class);
    }
    @Override
    public void marshal(Object value, HierarchialStreamWriter writer, MarshallingContext context) {
        ??? - no clue here
    }
    @Override
    public Object unmarshal(HierarchialStreamReader reader, UnmarshallingContext context) {
        ??? - no clue here
    }
}
然后,创建映射器并使用它:
XStream mapper = new XStream(new JettisonMappedXmlDriver());
mapper.registerConverter(new MyStateEnumConverter);
SomeJson jsonObj = mapper.fromXML(jsonString);
// Should print "closed"
System.out.println(jsonObject.getObject1().getMyState().getDesc());

我如何实现marshalunmarshal,以便我得到所需的映射?提前感谢!

您可以通过以下两件事来完成:

  1. 添加查找方法以及toString()覆盖到你的enum (MyStateEnum);和
  2. 扩展XStream的AbstractSingleValueConverter而不是实现Converter

MyStateEnum:

public enum MyStateEnum {
    // Everything you had is fine
    // But now, add:
    public static MyStateEnum getMyStateByDesc(String desc) {
        for(MyStateEnum myState : MyStateEnum.values())
            if(myState.getDesc().equals(desc))
                return myState;
        return null;
    }
    @Override
    public String toString() {
        return getDesc();
    }
}

MyStateEnumConverter:

public class MyStateEnumConverter extends AbstractSingleValueConverter {
    @Override
    public boolean canConvert(Class clazz) {
        return clazz.equals(MyStateEnum.class);
    }
    @Override
    public Object fromString(String parsedText) {
        return MyStateEnum.getMyStateByDesc(parsedText);
    }
}

通过将getMyStateByDesc(String)添加到枚举中,现在可以通过提供desc字符串从外部查找所有不同的枚举值。MyStateEnumConverter(扩展了AbstractSingleValueConverter)在底层使用toString()重写来将MyStateEnum实例与文本字符串关联。

所以当XStream解析JSON时,它看到一个JSON对象,比如"opened",这个新的转换器知道将"opened"传递给转换器的fromString(String)方法,该方法反过来使用getMyStateByDesc(String)来查找适当的enum实例。

不要忘记用XStream实例注册您的转换器,正如您在原始问题中已经显示的那样。

你可以使用EnumToStringConverter

文档

例子
@XStreamConverter(EnumToStringConverter.class)
public enum MyStateEnum {
enter code here
...

使用xstream.autodetectAnnotations (true)

为什么使用xstream来支持json ?你还有其他一些专门处理json的库,它们做得很好。json.

试试例如Genson,它可以开箱即用。json流中的值将是"Close", "Indeterminate"等,当反序列化时,它将产生正确的enum。

class SomeObject {
   private MyState state;
   ...
}
Genson genson = new Genson();
// json = {"state" : "Indeterminate"}
String json = genson.serialize(new SomeObject(MyState.Indeterminate));
// deserialize back
SomeObject someObject = genson.deserialize(json, SomeObject.class);
// will print unknown
System.out.println(someObject.getDesc());

最新更新