javajacksonobjectmapperjson-serialization

I can't get the Jackson object mapper to set the type correctly


I have this json:

{
 "List": [
  {
   "Field1": 1678493915,
   "Field2": "A string"
  }
 ]
}

When I define this method in a helper class:

  public static Map<String, List<Map<String, String>>> readJSON(String json) throws JsonProcessingException {
      return new ObjectMapper().readValue(json, new TypeReference<>() {});
  }

The field Field1 is parsed as a String as I want. But I want to make the method generic enough to be used in other places so I wrote this one in the helper class:

  public static <T> T readJSON2(String json) throws JsonProcessingException {
      return new ObjectMapper().readValue(json, new TypeReference<>(){});
  }

And I called:

Map<String, List<Map<String, String>>> data = readJSON2(jsonString);

Unluckily in this case Field1 is parsed as an Integer.

I can do the following in the helper class:

  public static <T> T readJSON3(String json, TypeReference<T> typeReference) throws JsonProcessingException {
      return new ObjectMapper().readValue(json, typeReference);
  }

And call it in this way:

Map<String, List<Map<String, String>>> data = readJSON3(jsonString, new TypeReference<>(){});

This works (Field1 is being parsed as String), but I would really like to encapsulate all the Jackson stuff like TypeReference in the helper class. This is, I don't want the caller to use TypeReference. Any idea?

Thanks in advance.


Solution

  • Read the article: https://www.baeldung.com/jackson-linkedhashmap-cannot-be-cast (paragraph 6). There are the limits to use generic types due to runtime nature.

    As I see, you can use solution such as:

    public class Program {
        private static final ObjectMapper mapper = new ObjectMapper();
    
        public static void main(String[] args) throws IOException {
            String json = "{\n" +
                    " \"List\": [\n" +
                    "  {\n" +
                    "   \"Field1\": 1678493915,\n" +
                    "   \"Field2\": \"A string\"\n" +
                    "  }\n" +
                    " ]\n" +
                    "}";
            
            Map<String, List<CustomType>> res = func(json, CollectionCustomType.class);
    
        }
    
        private static <T> T func(String json, Class<T> type) throws IOException {
            JavaType javaType = mapper.getTypeFactory().constructType(type);
            return mapper.readValue(json, javaType);
    
        }
    
    
        @Data
        private static class CustomType {
    
            @JsonProperty("Field1")
            private String field1;
    
            @JsonProperty("Field2")
            private String field2;
        }
        
        private static class CollectionCustomType extends HashMap<String, List<CustomType>> {}
    }