Home > Net >  How to create generic method for ObjectNode put
How to create generic method for ObjectNode put

Time:12-17

I have a use case where I need to support multiple types of values to be inserted into the ObjectNode (of Jackson ObjectMapper), however when I try to use generics it has errors Cannot resolve method 'put(java.lang.String, T)'

    public static <T> JsonNode of(String key, T value) {
        ObjectMapper objectMapper = new ObjectMapper();
        ObjectNode root = objectMapper.createObjectNode();
        root.put(key, value); // <== error shows up on this line


        return root;
}

The underlying ObjectNode does support many types for the value, e.g. <String, Boolean>, <String, String>, <String, Integer>, etc.

For full documentation Jackson

What's the correct way to do this? Thanks.

CodePudding user response:

The problem is that through type erasure, the compiler will produce the method below for your generic method.

    public static JsonNode of(String key, Object value) {
        ObjectMapper objectMapper = new ObjectMapper();
        ObjectNode root = objectMapper.createObjectNode();
        root.put(key, value); // <== error shows up on this line
        return root;
}

Per Jackson documentation, there's no such method put(String key, Object value).

Instead of calling the method of(String key, T value), I would just do the following:

  ObjectNode root = new ObjectMapper().createObjectNode();
  root.put(key, value);

Or you could write write several overloaded methods of(...).

CodePudding user response:

There is another approach that works for any json object:

Map<String, Object> map = new ObjectMapper().readValue(json, new TypeReference<HashMap<String,Object>>() {});

The object in the value can be any value object (String, Integer, etc), another Map<String, Object> as a nested object or a List<Object>/List<Map<String, Object>> and so on down to any depth.

CodePudding user response:

If you look at the signature of the ObjectNode#put method you will see that

public JsonNode put(String fieldName, JsonNode value)

the second argument is actually bound to a specific type and it is JsonNode , not just any T (much like your method allows).

So, because of the type erasure - the compiler has to ensure you provided a compatible type at compile time and I suggest you to put a suitable bound on the method, for example:

public static <T extends JsonNode> JsonNode of(String key, T value) {
    ObjectMapper objectMapper = new ObjectMapper();
    ObjectNode root = objectMapper.createObjectNode();
    root.set(key, value);

    return root;
}

making sure your method accepts only JsonNode or its descendants.


Small note 1: it is not a good thing to instantiate ObjectMapper every time the method gets called as it is a bit expensive object to create, better to make it a field.

Small note 2: The method ObjectNode#put gets deprecated since version 2.4, and it is recommended to use ObjectNode#set instead.

  • Related