Environment:
I use spring boot version 2.3.3.RELEASE
Problem
I register custom deserializers with @JsonComponent
annotation.
In some modules and tests I @Autowire
jacksons ObjectMapper
.
Problem 1: I cannot @Autowire ObjectMapper in @JsonComponent or the @JsonComponent will be ignored completely (without error message)
Problem 2: I want to have the same instance of ObjectMapper in @JsonComponent (or at least OM with same configuration) that I can obtain by Autowire in other Components
Example
Since I don't want custom deserialization for some fields I use the ObjectMapper to use convertValue()
in my custom deserializers.
I noticed, that I cannot @Autowire
the ObjectMapper in any of my Deserializers or the Configuration will not be picked up for other ObjectMappers that are autowired in my Application (So the Deserializers are not registered correctly)
I'm obtaining the ObjectMapper in the Deserializer with (ObjectMapper) jsonParser.getCodec();
But this ObjectMapper is not configured correctly (meaning e.g. annotations on class/methods are ignored).
I want to deserialize my object as follows:
@Test
void testDeserializeFoo() throws IOException {
ObjectMapper om = new ObjectMapper(); // this is obtained by jsonParser in deserializer but it behaves the same, since the ObjectMapper lacks the configuration
InputStream is = getClass().getResourceAsStream("/json/foo.json");
JsonNode fooNode = om.readTree(is);
Foo foo = om.convertValue(fooNode, Foo.class);
log.info("Foo: " + foo);
}
The constructor of Foo is annotated with @JsonCreator
.
The Problem is, that this annotation is ignored by the ObjectMapper I get from the parser in the custom Deserializer. This results in the following error message:
Invalid type definition for type
Foo
: Argument #0 has no property name, is not Injectable: can not use as Creator [constructor for Foo, annotations: {interface com.fasterxml.jackson.annotation.JsonCreator=@com.fasterxml.jackson.annotation.JsonCreator(mode=DEFAULT)}]
Is it possible to have the same instance of ObjectMapper in my custom Deserializer that is used in other Components when Autowired?
Edit
Possible Solution / Test:
I was testing my deserializer like this:
private JsonParser getJsonParser(String resource) throws IOException {
InputStream src = getInputStream(resource);
return objectMapper.createParser(src);
}
@Test
void testDeserializeFoo() throws IOException {
JsonParser parser = getJsonParser("/json/foo.json");
Foo foo = deserializer.deserialize(parser, null);
System.out.println(foo);
}
The problem was that the objectMapper in getParser() method was a new instance all the time. Now I use the autowired objectMapper. But how does this have any effect?
Conclusion:
I want to use the same instance of ObjectMapper in my JsonComponents (custom deserializers) as the Autowired ObjectMapper (which is provided by spring in other Components), or at least an ObjectMapper with the same configuration.
With configuration I mean: Enabled Jackson Features / Annotation Configurations on classes, methods, fields / registered modules and JsonComponents
Can someone please explain:
- how and when ObjectMapper is configured in Spring (when are Annotation configurations (JsonCreator, JsonProperty), Feature configurations (like accepting upper case) in application.yml, Custom JsonComponents etc registered on an ObjectMapper
- what is the lifecycle of this objectMapper instance?
- What is the lifecycle of a ContextConfiguration, DeserializationConfiguration?
- How does Spring and Jackson context relate to each other?
I looked for related topics, other answers related where:
- Spring and Jackson context are not the same (but why, what does this mean?)
- You need a HandlerInstantiator to Autowire (this is already default in my spring version I assume, also this does not explain why my custom deserializers are not picked up without any error messages when autowiring ObjectMapper in one of the deserializers)