Im trying to override the default KeyDeserializer but it seems to work only on top level key:
The input JSON
{
"upper_key":
{
"lower_key": "lower_value",
"lower_key_2": "lower_value_2"
},
"upper_key_2": "upper_value_2"
}
The mapper I use
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addKeyDeserializer(Object.class, new MyKeyParser());
mapper.registerModule(module);
Map<String, Object> map = mapper.readValue(jsonString, Map.class);
and the KeyDeserializer
public class MyKeyParser extends KeyDeserializer {
@Override
public String deserializeKey(String key, DeserializationContext deserializationContext) {
System.out.println(key);
return key;
}
}
The print output for the given json is:
upper_key
upper_key_2
What I expected it to be (order doesn’t matter)
upper_key
lower_key
lower_key_2
upper_key_2
What I’m missing?
EDIT:
I see some answers give alternative ways to get the keys but this is not the question.
I want to understand how to use the KeyDeserializer.
My real intent is to alter the keys – for example add suffix. so I don’t want to iterate over the map twice and create 2 maps.
I know I can write a Map.class Deserializer and do everything there. But the question is why the KeyDeserializer work only on top level keys and not how to manipulate maps.
Thank you
4
Answers
There is no need for overriding a Deserializer. For dynamic JSONs you could simply use a JsonNode and then parse the structure however you want afterwards:
prints:
KeyDeserializer call deserialize Key just for upper key. but you can get all keys by creating your own implementation for example
and call it from your main class
Let’s look at KeyDeserializer javadoc:
Note word keys here. KeyDeserializer is used only for map keys deserialization. In your case your target type is
Map<String, Object>
. Any other types aren’t affected by KeyDeserializer. That is the reason why your code behaves like that. Jackson basically does next steps:With your initial JSON it is impossible to apply key deserializer so lower keys will be affected by key deserializer: you need to have Map type instead of object. If you will use next JSON (I removed second upper key from original JSON because I want object to strictly match Map<String, Map<String, String>>):
and next code (Note that key deserializer registered for Object type, and map typed as "Object to Map", i.e. "Object to Map<Object, Object>"):
output will be as you want:
The fact that Jackson doesn’t use the
KeyDeserializer
for nested objects is explained by Le0pold’s answer.However, there is a trick to make it work as expected (tested with Jackson 2.12.7): call
addAbstractTypeMapping()
like this:Output: