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:
I looked for related topics, other answers related where:
In general you can use Jackson2ObjectMapperBuilder and build() to generate new object mapper instance with all the recent settings applied. The default ObjectMapper is provided by JackonsObjectMapperConfiguration in JackonAutoConfiguration. All jackson2 object mapper builder instances are created by JacksonObjectMapperBuilderConfiguration in JacksonAutoConfiguration. Details on configuring object mapper can be found here
You can further customize jackson2 object mapper builder using Jackson2ObjectMapperBuilderCustomizerConfiguration if you don't like the standard defaults in JacksonAutoConfiguration
Checkout this answer - it will answer your other questions
Coming to issue - Had the same issue when using jackson2objectbuilder/build or autowiring object mapper for ser/deser annotated with JsonComponent annotation. All these annotations are scanned by JsonComponentModule bean defined in JacksonAutoConfiguration and are registered with default object mapper and all the instances created by jackson2 object mapper builder. So it is not possible to use the not built object mapper and register the ser/deser at the same time. You are right the exception ( beancurrentlyincreationexception ) is suppressed by spring and json component module is not registered with message unresolvale circular reference for object mapper.
I didn't find any solution other than creating a new object mapper outside of spring managed.
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