将可变(原始/对象)JSON属性反序列化为使用Jackson的对象
给出具有可变属性(例如 label )的JSON对象,该属性可以是原始值(例如字符串)或对象.假设的用例可能是标签的多重翻译的包装:
Given a JSON object having a mutable property (e.g. label) which can be either primitive value (e.g. string) or an object. A hypothetical use-case could be a wrapper for pluralized translation of a label:
{
"label": "User name"
}
或
{
"label": {
"one": "A label",
"other": "The labels"
}
}
目标是使 Jackson 反序列化始终在Java端返回固定的结构.因此,如果给出了原始值,则该值总是会转换为目标POJO的某个属性(例如 other ),即:
The goal is to bring Jackson deserialization always return a fixed structure on the Java-side. Thus, if a primitive value is given it is always translated to a certain property (e.g. other) of the target POJO, i.e.:
public class Translations {
@JsonDeserialize(using = PluralizedTranslationDeserializer.class)
public PluralizedTranslation label;
}
public class PluralizedTranslation {
public String one;
public String other; // used as default fields for primitive value
}
当前,通过使用自定义 JsonDeserializer
会检查该属性是否为原始类型:
Currently the issue is solved by using a custom JsonDeserializer
which checks whether the property is primitive or not:
public class PluralizedTranslationDeserializer extends JsonDeserializer {
@Override
public PluralizedTranslation deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
ObjectCodec oc = jsonParser.getCodec();
JsonNode node = oc.readTree(jsonParser);
PluralizedTranslation translation;
if (node.isTextual()) {
translation = new PluralizedTranslation();
translation.other = node.asText();
} else {
translation = oc.treeToValue(node, PluralizedTranslation.class);
}
return translation;
}
}
是否有一种更优雅的方法来处理可变的JSON属性,而无需在节点级别运行解码器?
Is there a more elegant approach for handling mutable JSON properties without having a decoder which operates on node level?
您可以使label
设置器更通用,并添加一些处理这两种情况的逻辑.
You could make the label
setter more generic and add some logic handling the two cases.
public class Translations {
// Fields omitted.
@JsonProperty("label")
public void setLabel(Object o) {
if (o instanceof String) {
// Handle the first case
} else if (o instanceof Map) {
// Handle the second case
} else {
throw new RuntimeException("Unsupported");
}
}
}
替代解决方案,它将工厂方法放在PluralizedTranslation
类中,而使Translations
类不受影响:
Alternative solution, which places the factory method inside the PluralizedTranslation
class, leaving the Translations
class unaffected:
public class PluralizedTranslation {
public String one;
public String other; // used as default fields for primitive value
@JsonCreator
private PluralizedTranslation(Object obj) {
if (obj instanceof Map) {
Map map = (Map) obj;
one = (String) map.get("one");
other = (String) map.get("other");
} else if (obj instanceof String) {
other = (String) obj;
} else {
throw new RuntimeException("Unsupported");
}
}
}
请注意,可以将构造函数标记为private
,以防止意外使用.
Note that the constructor can be marked as private
to prevent unintended usage.