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.