我正在尝试结合Jackson的一些功能,以便可以将json中的{type,value}
对反序列化为Java中表示所有信息的Union类型,但无法解决该问题。帮助将不胜感激。
这就是我正在使用的东西:
noyes
和offon
都是boolean
类型。{type, value}
,但不是强类型语言。noyes -> noYesValue
,float -> floatValue
我有一个看起来像这样的json文档:
{
"obj": [
{
"type": "noyes",
"value": true",
"id": 1
}, {
"type": "offon",
"value": false,
"id": 2
}, {
"type": "text",
"value": "hello",
"id": 3
}, {
"type": "float",
"value": 1.2,
"id": 4
}, {
"type": "times",
"value": [{"s": "12:22", "e": "16:00"}]
"id": 5
}
]
}
和如下所示的Java类:
class Response {
List<Item> obj;
}
class Item {
int id;
Value value;
}
class Value {
enum Fields { NO_YES_VALUE, OFF_ON_VALUE, TEXT_VALUE, FLOAT_VALUE, TIMES_VALUE }
static Item noYesValue(boolean noYes) {...}
static Item offOnValue(boolean offOn) {...}
static Item textValue(String text) {...}
static Item floatValue(float value) {...}
static Item timesValue(List<TimesValue> times) {...}
Fields setField;
Object fieldValue;
Value() {}
Value(Fields field, Object value) {setFieldValue(field, value);}
Fields getSetField() { return setField; }
Object getFieldValue() { return fieldValue; }
void setFieldValue(Fields field, Object value) {
// checkType(field, value);
this.setField = field;
this.fieldValue = value;
}
// these do have checks for the set field, types, null, etc
boolean getNoYesValue() { return (Boolean) fieldValue; }
void setNoYesValue(boolean v) { setField = NO_YES_VALUE; fieldValue = v; }
boolean getOffOnValue() { return (Boolean) fieldValue; }
void setOffOnValue(boolean v) { setField = OFF_ON_VALUE; fieldValue = v; }
// ...
}
class TimesValue {
String startTime;
String endTime;
}
对于Java类,以下是等效的:
Value.noYesValue(false);
new Value().setNoYesValue(false);
new Value().setFieldValue(NO_YES_VALUE, false);
new Value(NO_YES_VALUE, false);
以下是等效的:
value.getNoYesValue();
(Boolean) value.getFieldValue();
经过更多的挖掘和反复试验后,我设法变得比以前更远了。
首先,我将Value
展平为Item
interface ItemMixin {
@JsonUnwrapped Value getValue();
}
这提升了我所有的Value
属性,因此它们成为Item
类的一部分,相当于{"value": {"type": "offon", "value": false}}
成为{"type": "offon", "value": false}
接下来,我需要处理那个Fields
枚举,为此,我编写了一个自定义的反序列化器,看起来像这样,并将其注册到模块中
new StdDeserializer<Value.Fields>(Value.Fields.class) {
@Override
public Value.Fields deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
String type = p.getText();
switch (type) {
case "noyes": return Value.Fields.NO_YES_VALUE;
case "offon": return Value.Fields.OFF_ON_VALUE;
case "float": return Value.Fields.FLOAT_VALUE;
case "text": return Value.Fields.TEXT_VALUE;
case "times": return Value.Fields.TIMES_VALUE;
// ...
}
ctxt.handleWeirdStringValue(Value.Fields.class, type, "Unsupported Value type");
return null;
}
}
最后,我告诉Value
类型使用构造函数创建对象
static abstract class ValueMixin {
@JsonCreator
ValueMixin(@JsonProperty("type") Value.Fields type, @JsonProperty("value") Object value) {}
}
这给了我90%的需求,但是我现在遇到的问题是,它仅适用于基本类型(boolean
,String
等),我的times
字段只是反序列化为String
导致我的代码出现异常。
我尝试在@JsonTypeInfo
参数上使用@JsonSubTypes
和value
,为该字段创建一个属性,然后在其中放置注释,但无法使创建者正确解析类型。