【问题标题】:Custom Xstream/JSON converter for enum用于枚举的自定义 Xstream/JSON 转换器
【发布时间】:2013-01-11 17:59:59
【问题描述】:

我有以下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 以获得所需的映射?提前致谢!

【问题讨论】:

    标签: java json enums xstream oxm


    【解决方案1】:

    你可以通过做两件事来实现这一点:

    1. 添加查找方法以及toString() 覆盖到您的枚举(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) 来查找适当的枚举实例。

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

    【讨论】:

      【解决方案2】:

      您可以使用 EnumToStringConverter

      Documentation

      例子

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

      使用 xstream.autodetectAnnotations(true)

      【讨论】:

        【解决方案3】:

        为什么要使用 xstream 来支持 json?您还有几个专门用于 json 的其他库,并且做得很好。不带引号也关闭是无效的 json。

        试试Genson,它可以开箱即用。 json 流中的值将是“关闭”、“不确定”等,并且在反序列化时会产生正确的枚举。

        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());
        

        【讨论】:

        • 对错误问题的正确答案 - 我只是对这里的 XStream 感兴趣,JettisonMappedXmlDriver 非常适合 JSON。
        猜你喜欢
        • 1970-01-01
        • 2014-05-24
        • 1970-01-01
        • 2011-07-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-30
        • 1970-01-01
        相关资源
        最近更新 更多