How to Configure Jackson ObjectMapper for Camel in Spring Download

I am trying to serialize and deserialize POJO to JSON on Camel routes using Jackson. Some of them have Java 8 LocalDate fields, and I want them to be serialized as a YYYY-MM-DD string, and not as an array of integers.

We only use the Java configuration for our Spring Boot application, so there is no XML Camel configuration.

I have successfully created an ObjectMapper that does what I want, which is used by other parts of our system, adding this to our dependencies:

<dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> </dependency> 

and this matches our application configuration:

 @Bean public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) { return builder .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) .build(); } 

An example of an outbound REST route:

 @Component public class MyRouteBuilder extends RouteBuilder { @Override public void configure() throws Exception { restConfiguration().component("servlet").contextPath("/mycontext") .port(8080).bindingMode(RestBindingMode.json); rest("/myendpoint) .get() .route() .to("bean:myService?method=myMethod()"); } } 

An example of an incoming message route:

 @Component public class MyRouteBuilder extends RouteBuilder { @Autowired private MyBean myBean; @Override public void configure() { from(uri) .unmarshal().json(JsonLibrary.Jackson) .bean(myBean); } } 

However, by default, Camel creates its own instances of ObjectMapper, therefore it does not select JSR310 serializers / deserializers that are automatically added by Jackson2ObjectMapperBuilder or the WRITE_DATES_AS_TIMESTAMPS function is WRITE_DATES_AS_TIMESTAMPS . I read the Camel JSON documentation, but does not show how to add a custom DataFormat using the Spring configuration or how to apply a global setting for all types.

So, how can I say that Camel uses my ObjectMapper using only the Spring Java boot configuration?

+7
jackson spring-boot apache-camel
source share
6 answers

I found a solution by going through the Camel code. Therefore, when it does what I want, it may not work with future versions of Camel, as it seems undocumented and potentially unsupported.

All I do is add the following bean to my Spring config, in addition to my ObjectMapper bean in question:

 @Bean(name = "json-jackson") @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public JacksonDataFormat jacksonDataFormat(ObjectMapper objectMapper) { return new JacksonDataFormat(objectMapper, HashMap.class); } 

Key points to note:

  • There is no constructor for JacksonDataFormat that accepts an ObjectMapper without a non- ObjectMapper type. However, the default constructor uses HashMap.class when the unmarshal type is not provided, so I use this. For some magic, this seems to be then used to undo all types of POJOs. If you need more specific data formats for other classes, you will also need to install ObjectMapper in them.
  • The camel is looking for a search in the bean registry for the bean called "json-jackson", so setting up the Spring bean to use this name Camel tricks 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 receive a new instance of the DataFormat . See CAMEL-7880 .
+4
source share

Create JacksonDataFormat in Java code and enable / disable the necessary functions, and then use this instance in the Camel route.

  .unmarshal(myInstanceGoesHere). 
+2
source share

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 the CamelContextConfiguration class, autwiring JacksonDataFormat , to configure the detection of classpath modules and the configuration of serialization parameters:

 @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); } } 
+1
source share

I managed to configure ObjectMapper for Camel quite conveniently using org.apache.camel:camel-jackson-starter:2.20.0

It provides some useful ObjectMapper properties for configuration using Spring application properties. For example, WRITE_DATES_AS_TIMESTAMPS can be set directly from the application.yaml file or application.properties.

Look for the JacksonDataFormatConfiguration class for more details.

I also needed to use some Mixins, so I still needed to configure Camel to use W760> ObjectMapper. I ended up with this:

Bean configuration:

 @Bean public Jackson2ObjectMapperBuilderCustomizer customizer() { return new Jackson2ObjectMapperBuilderCustomizer() { @Override public void customize(Jackson2ObjectMapperBuilder builder) { builder.mixIn(Person.class, PersonMixin.class); } } } 

application.yaml:

 camel: dataformat: json-jackson: disable-features: WRITE_DATES_AS_TIMESTAMPS object-mapper: jacksonObjectMapper 

Where jacksonObjectMapper is the name of the ObjectMapper bean created by the configured Jackson2ObjectMapperBuilder

+1
source share

If Camel gives you problems, I will return to using beans directly:

  • Just create a small Json utility that can sort and disassemble and automatically create a pre-configured ObjectMapper into it.

  • Intelligent integration with Camels Spring bean scammers to call your utility and convert the message to a route, for example:

      from(uri) .unmarshal().json(JsonLibrary.Jackson) .beanRef("jsonUtil", "unmarshal") .bean(myBean); 
0
source share

So far, the only @ david-edwards sentence has worked for me. First, I defined the bean data format with the id: "json-jackson"

 <bean id="json-jackson" class="com.mydomain.JacksonDataFormatExt" /> 

Then the format class:

 public class JacksonDataFormatExt extends JacksonDataFormat{ public JacksonDataFormatExt(){ super(); setPrettyPrint(true); setEnableFeatures(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS.name()); SimpleModule s = new SimpleModule(); s.addSerializer(CustomEnum.class, new CustomEnumSerializer()); addModule(s); } } 

And the CustomEnumSerializer class:

 public class CustomEnumSerializer extends JsonSerializer<CustomEnum> { @Override public void serialize(CustomEnumvalue, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { String stringValue = value.getNlsText(); if(stringValue != null && !stringValue.isEmpty() && !stringValue.equals("null")) { jgen.writeString(stringValue); } else { jgen.writeNull(); } } } 
0
source share

All Articles