使用Jackson将可变(原始/对象)JSON属性反序列化为对象

时间:2017-02-13 13:41:40

标签: java json jackson deserialization

给定具有可变属性的JSON对象(例如 label ),其可以是原始值(例如字符串)或对象。假设用例可以是标签复数翻译的包装器:

{
   "label": "User name"
}

{
   "label": {
       "one": "A label",
       "other": "The labels"
   }
}

目标是使Jackson反序列化始终在Java端返回一个固定的结构。因此,如果给出原始值,它总是被转换为目标POJO的某个属性(例如其他),即:

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来解决问题,该自定义Apache Lucene检查属性是否为原始属性:

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属性而无需在节点级别上运行的解码器?

1 个答案:

答案 0 :(得分:2)

您可以使label setter更通用,并添加一些处理这两种情况的逻辑。

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类不受影响:

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以防止意外使用。