How to configure Jackson ObjectMapper for Camel in Spring Boot
I have found a solution by stepping through the Camel code. So while it does what I want, it might not work with future versions of Camel since it appears to be undocumented and potentially unsupported.
All I do is add the following bean to my Spring config, in additional to my ObjectMapper
bean in the question:
@Bean(name = "json-jackson")
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public JacksonDataFormat jacksonDataFormat(ObjectMapper objectMapper) {
return new JacksonDataFormat(objectMapper, HashMap.class);
}
The crucial points to note:
- There is no constructor for
JacksonDataFormat
that takes anObjectMapper
without an unmarshal type. However, in the default constructor aHashMap.class
is used when no unmarshal type is provided, so I use that. By some magic, this appears to then get used to unmarshal all POJO types. If you also need more specific data formats for other classes, you will need to set theObjectMapper
in them too. - Camel appears to search the bean registry for a bean called "json-jackson", so setting the Spring bean to use that name tricks Camel into not creating a new one and using mine instead.
- The bean scope must be set to
SCOPE_PROTOTYPE
because the REST DSL expects to get a new instance of theDataFormat
. See CAMEL-7880.
Good news everyone, object mapper autodiscovery is supported now for Spring Boot! Simply set this property:
camel.dataformat.json-jackson.auto-discover-object-mapper=true
If set to true then Jackson will lookup for an objectMapper into the registry
Docs: https://camel.apache.org/components/latest/dataformats/json-jackson-dataformat.html#_spring_boot_auto_configuration
Logs:
INFO o.a.c.impl.engine.AbstractCamelContext : Apache Camel 3.3.0 (CamelContext: camel-1) is starting
INFO o.a.c.c.jackson.JacksonDataFormat : Found single ObjectMapper in Registry to use: com.fasterxml.jackson.databind.ObjectMapper@20a1b3ae
WARN o.a.c.c.jackson.JacksonDataFormat : The objectMapper was already found in the registry, no customizations will be applied
(the warning just denotes, that all your other properties under camel.dataformat.json-jackson.*
are ignored)
Update 17.08.2022
For new versions of Camel since 3.15.0
use different property
camel.dataformat.jackson.auto-discover-object-mapper=true
Create the JacksonDataFormat
in java code and enable/disable the features you want, and then use that instance in the Camel route.
.unmarshal(myInstanceGoesHere).
This is an example when using marshal
, the same can be adapter with unmarshal
:
CamelContext ctx = new DefaultCamelContext();
JacksonDataFormat df = new JacksonDataFormat();
df.setModuleClassNames("com.fasterxml.jackson.datatype.jsr310.JavaTimeModule");
ctx.addRoutes(
new RouteBuilder() {
@Override
public void configure() {
from("direct:start").marshal(df).log("Out");
}
});
Using Spring and Camel 2.18.1, I was able to achieve the same by adding the following dependencies:
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.6.1</version>
</dependency>
and in a CamelContextConfiguration
class, autowiring the JacksonDataFormat
in order to configure the discovery of classpath modules and the configuration of the serialization options:
@Configuration
public class CamelContextConfig implements CamelContextConfiguration {
@Autowired
public JacksonDataFormat jacksonDataFormat;
@Override
public void beforeApplicationStart(CamelContext camelContext) {
}
@Override
public void afterApplicationStart(CamelContext camelContext) {
jacksonDataFormat
.getObjectMapper()
.findAndRegisterModules()
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
}