Custom JSON field deserialization using Jackson
I am using Jackson to deserialize some JSON and I ran into some problems when trying to use my own deserializer for one of the fields.
class MyClass
{
private static class SpecialPropertyDeserializer extends JsonDeserializer<SpecialProperty>
{
@Override
public SpecialProperty deserialize(JsonParser jsonParser,
DeserializationContext deserializationContext) throws IOException, JsonProcessingException
{
// do some custom deserialisation
}
}
private static class SpecialProperty
{
private String m_foo;
private String m_bar;
@JsonCreator
SpecialProperty(@JsonProperty("foo") String foo,
@JsonProperty("bar") String bar)
{
m_foo = foo;
m_bar = bar;
}
}
private String m_identifier;
private String m_version;
@JsonDeserialize(using = SpecialPropertyDeseializer.class)
private SpecialProperty m_specialProperty;
@JsonCreator
MyClass(@JsonProperty("identifier") String identifier,
@JsonProperty("version") String version,
@JsonProperty("specialProperty") SpecialProperty specialProperty)
{
m_identifier = identifier;
m_version = version;
m_specialProperty = specialProperty;
}
}
and this is JSON, I want to deserialize:
{
"identifier" : "some-id",
"version" : "1.7",
"specialProperty" : {
"foo" : "str1",
"bar" : "str2"
},
}
I call the cartographer like this:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
return objectMapper.readValue(input, MyClass.class);
I've observed the following behavior:
- Without a special property, everything works fine - i.e. removes all references to
SpecialProperty
from code and JSON. - If I have included
SpecialProperty
in JSON but removed the custom deserializer for it then it works fine too. Ctor forSpecialProperty
. - It doesn't work with a custom deserializer. The ctor is called for
SpecialProperty
, but the custom deserializer is not.
What am I doing wrong?
source to share
@JsonDeserialize
annotation can be placed in field, setter or class. Jackson will take this into account if what is being annotated is used to set a value.
Eg1. It notices @JsonDeserialize
above the installer if it uses the installer to set the field value.
Eg2 It notices @JsonDeserialize
above a field if it directly sets that field without using a setter or constructor.
It will tend to take this into account if it is of a class, unless overridden by a more specific annotation on the field or setter docs.I believe the docs might be clearer on the above details.
In your case, you have an annotation on a field SpecialProperty
, but you set that field in the constructor MyClass
to be ignored.
In this case, you can move @JsonDeserialize
on top of the class instead of the field. This is probably the simplest solution in your case. For example.
@JsonDeserialize(using = MyClass.SpecialPropertyDeserializer.class)
private static class SpecialProperty {
Or you can skip the annotation altogether and register the deserializer on the crankcase. Make SpecialProperty
and SpecialPropertyDeserializer
not private in first MyClass
, and then:
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(MyClass.SpecialProperty.class, new MyClass.SpecialPropertyDeserializer());
objectMapper.registerModule(module);
You can also get rid of the constructor MyClass
and the current field annotation SpecialProperty
will be taken into account.
source to share