camel-quarkus icon indicating copy to clipboard operation
camel-quarkus copied to clipboard

JSON/Jackson: How to configure JavaTimeModule in Quarkus Camel?

Open tmulle opened this issue 2 years ago • 4 comments

Hi,

Just started using Quarkus-Camel and am still learning how things work.

I am trying to serialize a POJO with LocalDateTime and getting the error below.

I've done a ton of searching and found various answers for Quarkus itself here: https://quarkus.io/guides/rest-json#about-serialization

I've tried both options to provide an ObjectMapper configuration and I still get the error.

I've included the dependency as well:

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

I also looked here: https://camel.apache.org/components/3.20.x/dataformats/jackson-dataformat.html but didn't find anything useful. I tried to set the module class parameter in application.properties but that didn't seem to help.

camel.dataformat.jackson.auto-discover-object-mapper = true
camel.dataformat.jackson.module-class-names = com.fasterxml.jackson.datatype.jsr310.JavaTimeModule

Any ideas how to get this to work? It will be helpful in the future should I need to add other configuration options.

 com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.LocalDateTime` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: com.acme.SnapshotEntity["uploadDate"])
        at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
        at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1306)
        at com.fasterxml.jackson.databind.ser.impl.UnsupportedTypeSerializer.serialize(UnsupportedTypeSerializer.java:35)
        at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:733)
        at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:774)
        at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
        at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
        at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
        at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1572)
        at com.fasterxml.jackson.databind.ObjectWriter._writeValueAndClose(ObjectWriter.java:1273)
        at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:1098)
        at org.apache.camel.component.jackson.AbstractJacksonDataFormat.marshal(AbstractJacksonDataFormat.java:155)
        at org.apache.camel.support.processor.MarshalProcessor.process(MarshalProcessor.java:64)
        at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$SimpleTask.run(RedeliveryErrorHandler.java:477)
        at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:181)
        at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:59)
        at org.apache.camel.processor.Pipeline.process(Pipeline.java:175)
        at org.apache.camel.impl.engine.CamelInternalProcessor.process(CamelInternalProcessor.java:392)
        at org.apache.camel.component.platform.http.vertx.VertxPlatformHttpConsumer.lambda$handleRequest$2(VertxPlatformHttpConsumer.java:193)
        at io.vertx.core.impl.ContextBase.lambda$null$0(ContextBase.java:137)
        at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:264)
        at io.vertx.core.impl.ContextBase.lambda$executeBlocking$1(ContextBase.java:135)
        at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
        at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
        at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:833)

tmulle avatar Jan 16 '23 21:01 tmulle

Are you using the Camel REST DSL? If so, try this in your RouteBuilder:

restConfiguration().dataFormatProperty("autoDiscoverObjectMapper", "true");

jamesnetherton avatar Jan 18 '23 09:01 jamesnetherton

There is more information on the Camel Quarkus Jackson page. Inspired by this answer on StackOverflow, you can add the following to your RouteBuilder if not using REST DSL:

JacksonDataFormat df = new JacksonDataFormat();
df.setModuleClassNames("com.fasterxml.jackson.datatype.jsr310.JavaTimeModule");
df.setAutoDiscoverObjectMapper(true);

Then add marshal(df) to your route, for example:

from("direct:start").marshal(df).log("${body}");

djcoleman avatar Jan 18 '23 10:01 djcoleman

Thanks for the info, unfortunately it still doesn't appear to be working. I am using the REST DSL and added the properties you mentioned but I still get the same error.

It appears that manually creating the JacksonDataFormat and changing my marshaling from .marshal().json to just .marshal(df) as suggested by @djcoleman seems to work and the JSON is rendered.

Just wish it would work using the REST DSL.. seems like it should but I see from other Stack Overflow posts people having issues as well using the REST DSL, even with SpringBoot. There are very few posts about Camel and Quarkus. Most results are using SpringBoot.

This doesn't work..

Marshalling from("direct:displayAll").process(this::displayAll).marshal().json();

REST DSL config

restConfiguration()
                .contextPath("/archive")
                .skipBindingOnErrorCode(true)
                .enableCORS(true)
                .dataFormatProperty("prettyPrint", "true")
                .dataFormatProperty("autoDiscoverObjectMapper", "true")
                .dataFormatProperty("moduleClassNames", "com.fasterxml.jackson.datatype.jsr310.JavaTimeModule");

But this does work:

REST DSL Config

restConfiguration()
                .contextPath("/archive")
                .enableCORS(true);

Marshalling from("direct:displayAll").process(this::displayAll).marshal(df);

Manually Creating the JacksonDataFormat

JacksonDataFormat df = new JacksonDataFormat();
        df.setModuleClassNames("com.fasterxml.jackson.datatype.jsr310.JavaTimeModule");
        df.setAutoDiscoverObjectMapper(true);

tmulle avatar Jan 18 '23 14:01 tmulle

I was having the same problem using Spring Boot. My issue was that I didn't have the following Maven dependency:

 <dependency>
 	<groupId>org.apache.camel.springboot</groupId>
 	<artifactId>camel-jackson-starter</artifactId>
 </dependency>

Without it there is no support for auto configuration. In result, the configuration

camel.dataformat.jackson.module-class-names = com.fasterxml.jackson.datatype.jsr310.JavaTimeModule

in application.properties was ignored.

grigoriliev avatar Sep 14 '23 11:09 grigoriliev