简体   繁体   English

枚举的自定义Xstream / JSON转换器

[英]Custom Xstream/JSON converter for enum

I have the following Enum : 我有以下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;
    }
}

I am trying to write an XStream Converter that will know to map back a JSON element " mystate " to a MyState instance. 我正在尝试编写一个XStream Converter ,它将知道将JSON元素“ mystate ”映射回MyState实例。

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

This should produce, amongst other objects ( someJson and object1 ) a MyState.Close instance. 除了其他对象( someJsonobject1 )之外,这MyState.Close产生MyState.Close实例。 I've started the Converter , but haven't gotten very far: 我已经启动了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
    }
}

Then, to create the mapper and use it: 然后,创建映射器并使用它:

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

How can I implement marshal and unmarshal so thatI get the desired mapping? 我怎样才能实现marshalunmarshal这样thatI获得所需的映射? Thanks in advance! 提前致谢!

You can accomplish this by doing 2 things: 您可以通过执行以下两项操作来完成此操作:

  1. Adding a lookup method as well as a toString() override to your enum ( MyStateEnum ); 向您的枚举( MyStateEnum )添加一个查找方法以及一个toString()重写; and
  2. Extending XStream's AbstractSingleValueConverter instead of implementing Converter 扩展XStream的AbstractSingleValueConverter而不是实现Converter

MyStateEnum : 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 : 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);
    }
}

By adding getMyStateByDesc(String) to your enum, you now have a way to look up all the various enumerated values from the outside, by providing a desc string. 通过将getMyStateByDesc(String)添加到您的枚举中,您现在可以通过提供desc字符串,从外部查找所有各种枚举值。 The MyStateEnumConverter (which extends AbstractSingleValueConverter ) uses your toString() override under the hood to associate a MyStateEnum instance with a text string. MyStateEnumConverter (扩展了AbstractSingleValueConverter )在MyStateEnumConverter使用您的toString()重写将MyStateEnum实例与文本字符串相关联。

So when XStream is parsing the JSON, it sees a JSON object of, say, "opened", and this new converter knows to pass "opened" into the converter's fromString(String) method, which in turn uses getMyStateByDesc(String) to lookup the appropriate enum instance. 因此,当XStream解析JSON时,它会看到一个JSON对象,例如“ opened”,并且此新转换器知道将“ opened”传递到转换器的fromString(String)方法中,该方法又使用getMyStateByDesc(String)进行查找。适当的枚举实例。

Don't forget to register your converter with your XStream instance as you already showed in your original question. 别忘了像原始问题中已经显示的那样,将转换器注册到XStream实例中。

You can use the EnumToStringConverter 您可以使用EnumToStringConverter

Documentation 文档

Example

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

...

Use xstream.autodetectAnnotations(true) 使用xstream.autodetectAnnotations(true)

Why are you using xstream for json support? 为什么将xstream用于json支持? You have a couple of other libraries specialized in json and that do it well. 您还有几个专门用于json的其他库,它们做得很好。 Also closed without quotes is not valid json. 也关闭不带引号的无效json。

Try for example Genson , it will work out of the box. 例如尝试Genson ,它将立即可用 The values in the json stream would be "Close", "Indeterminate", etc and when deserializing it will produce the correct enum. json流中的值将为“ Close”,“ Indeterminate”等,并且在反序列化时将产生正确的枚举。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM