Search code examples
javajsonjacksonjson-deserialization

Deserialising different types to single field using Jackson


I have a following class that I want to use for deserializing JSON

public interface MyObject {

    @JsonProperty("prop")
    String prop;

    @JsonProperty("value")
    Double value();        // Need this to be either a double or a string or a Map
}

However, I want to be able to parse both the JSON with a double value

{
  prop: "myprop",
  value: 15.7
}

and a JSON with non Double value like a string or a map

{
  prop: "myprop1",
  value: {
    "attr1": "value1",
    "attr2": 12.0
  }
}

I looked at @JsonSubTypes annotation, but that looks like only useful for the cases where inheritance is involved. Is it possible to do it in Jackson? If so how can I define my Java class to achieve the same?


Solution

  • In general, I'd discourage the use of arbitrary types of data points. Having strong types gives plenty of benefits about which I can talk if you want. However, since you only talked about deserialization it might be that you are just reading such a JSON produced by someone else.

    The solution is quite simply: use Object field.

    public static class MyObject {
    
        @JsonProperty("prop")
        String prop;
    
        @JsonProperty("value")
        Object value;        // <- object
    }
    
    @Test
    public void testUnknownType() throws JsonProcessingException {
        final ObjectMapper objectMapper = new ObjectMapper();
        final MyObject object1 = objectMapper.readValue("{\n" +
            "  \"prop\": \"myprop\",\n" +
            "  \"value\": 15.7\n" +
            "}", MyObject.class);
        Assert.assertEquals(15.7d, object1.value);
        final MyObject object2 = objectMapper.readValue("{\n" +
            "  \"prop\": \"myprop1\",\n" +
            "  \"value\": {\n" +
            "    \"attr1\": \"value1\",\n" +
            "    \"attr2\": 12.0\n" +
            "  }\n" +
            "}", MyObject.class);
        Assert.assertTrue(object2.value instanceof Map);
    }