Deserialize mutable (primitive/object) JSON property to object with Jackson

自闭症网瘾萝莉.ら 提交于 2021-01-29 04:04:46

问题


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"
}

or

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

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
}

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;
    }
}

Is there a more elegant approach for handling mutable JSON properties without having a decoder which operates on node level?


回答1:


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");
        }
    }
}

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");
        }
    }
} 

Note that the constructor can be marked as private to prevent unintended usage.



来源:https://stackoverflow.com/questions/42205497/deserialize-mutable-primitive-object-json-property-to-object-with-jackson

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!