I have the following 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.
"someJson": {
"object1": {
"mystate": closed
}
}
This should produce, amongst other objects (someJson
and object1
) a MyState.Close
instance. I've started the Converter
, but haven't gotten very far:
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? Thanks in advance!
You can accomplish this by doing 2 things:
toString()
override to your enum (MyStateEnum
); andAbstractSingleValueConverter
instead of implementing 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);
}
}
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. The MyStateEnumConverter
(which extends AbstractSingleValueConverter
) uses your toString()
override under the hood to associate aMyStateEnum
instance with a text string.
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.
Don't forget to register your converter with your XStream
instance as you already showed in your original question.