I'm using Jackson to deserialize some JSON and I've run into some trouble while trying to use a custom 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 the JSON I want to deserialize:
{
"identifier" : "some-id",
"version" : "1.7",
"specialProperty" : {
"foo" : "str1",
"bar" : "str2"
},
}
I invoke the mapper as follows:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
return objectMapper.readValue(input, MyClass.class);
I've observed the following behaviour:
SpecialProperty
from the code and the JSON.SpecialProperty
in the JSON but remove the custom
deserializer for it then it also works fine. The ctor for
SpecialProperty
is called.SpecialProperty
is called but the custom deserializer is not.What am I doing wrong?
@JsonDeserialize
annotation can be placed on a field, a setter or a class. Jackson will take it into account if what is annotated is what it uses to set the value.
E.g.1 It will notice @JsonDeserialize
over a setter if it uses the setter to set the value of a field.
E.g.2 It will notice @JsonDeserialize
over a field if it directly sets this field without using a setter or a constructor.
It will tend to take it into account if it's on a class unless it's overridden by a more specific annotation on a field or setter docs. I reckon the docs could be clearer on the above details.
In your case you have the annotation over the SpecialProperty
field but you are setting this field in the MyClass
constructor so it's ignored.
In this case you can move @JsonDeserialize
over the class instead of over the field. That's probably the simplest solution in your case. E.g.
@JsonDeserialize(using = MyClass.SpecialPropertyDeserializer.class)
private static class SpecialProperty {
Or you can skip the annotation altogether and register the deserializer on the mapper. First make SpecialProperty
and SpecialPropertyDeserializer
non private in 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 constructor of MyClass
and the current annotation over the SpecialProperty
field will be taken into account.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With