Search code examples
jooqjooq-codegen-mavenjooq-codegen

jooq-jackson-extensions: Java 8 date/time type `java.time.OffsetDateTime` not supported


I'm using JOOQ 3.20.0-SNAPSHOT with this commit: 0596e787acbc444f00399edeaca28e05e7deed82. MRE is here: https://github.com/sify21/testjooq

mvn exec:java reports error:

org.jooq.exception.DataTypeException: Error while mapping JSON to POJO using Jackson
    at org.jooq.impl.Convert$ConvertAll.from (Convert.java:1397)
    at org.jooq.impl.Convert.convert0 (Convert.java:516)
    at org.jooq.impl.Convert.convert (Convert.java:591)
    at org.jooq.impl.DefaultConverterProvider.lambda$provide$1 (DefaultConverterProvider.java:125)
    at org.jooq.Converter$1.from (Converter.java:248)
    at org.jooq.impl.AbstractRecord.get (AbstractRecord.java:220)
    at com.test.App.main (App.java:49)
    at org.codehaus.mojo.exec.ExecJavaMojo.doMain (ExecJavaMojo.java:375)
    at org.codehaus.mojo.exec.ExecJavaMojo.doExec (ExecJavaMojo.java:364)
    at org.codehaus.mojo.exec.ExecJavaMojo.lambda$execute$0 (ExecJavaMojo.java:286)
    at java.lang.Thread.run (Thread.java:1583)
Caused by: java.lang.reflect.InvocationTargetException
    at jdk.internal.reflect.DirectMethodHandleAccessor.invoke (DirectMethodHandleAccessor.java:118)
    at java.lang.reflect.Method.invoke (Method.java:580)
    at org.jooq.impl.Convert$ConvertAll.from (Convert.java:1394)
    at org.jooq.impl.Convert.convert0 (Convert.java:516)
    at org.jooq.impl.Convert.convert (Convert.java:591)
    at org.jooq.impl.DefaultConverterProvider.lambda$provide$1 (DefaultConverterProvider.java:125)
    at org.jooq.Converter$1.from (Converter.java:248)
    at org.jooq.impl.AbstractRecord.get (AbstractRecord.java:220)
    at com.test.App.main (App.java:49)
    at org.codehaus.mojo.exec.ExecJavaMojo.doMain (ExecJavaMojo.java:375)
    at org.codehaus.mojo.exec.ExecJavaMojo.doExec (ExecJavaMojo.java:364)
    at org.codehaus.mojo.exec.ExecJavaMojo.lambda$execute$0 (ExecJavaMojo.java:286)
    at java.lang.Thread.run (Thread.java:1583)
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.OffsetDateTime` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling
 at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 70] (through reference chain: com.test.Address["built_time"])
    at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from (InvalidDefinitionException.java:67)
    at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition (DeserializationContext.java:1887)
    at com.fasterxml.jackson.databind.deser.impl.UnsupportedTypeDeserializer.deserialize (UnsupportedTypeDeserializer.java:48)
    at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet (FieldProperty.java:138)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize (BeanDeserializer.java:310)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize (BeanDeserializer.java:177)
    at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue (DefaultDeserializationContext.java:342)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose (ObjectMapper.java:4899)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue (ObjectMapper.java:3846)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue (ObjectMapper.java:3814)
    at jdk.internal.reflect.DirectMethodHandleAccessor.invoke (DirectMethodHandleAccessor.java:103)
    at java.lang.reflect.Method.invoke (Method.java:580)
    at org.jooq.impl.Convert$ConvertAll.from (Convert.java:1394)
    at org.jooq.impl.Convert.convert0 (Convert.java:516)
    at org.jooq.impl.Convert.convert (Convert.java:591)
    at org.jooq.impl.DefaultConverterProvider.lambda$provide$1 (DefaultConverterProvider.java:125)
    at org.jooq.Converter$1.from (Converter.java:248)
    at org.jooq.impl.AbstractRecord.get (AbstractRecord.java:220)
    at com.test.App.main (App.java:49)
    at org.codehaus.mojo.exec.ExecJavaMojo.doMain (ExecJavaMojo.java:375)
    at org.codehaus.mojo.exec.ExecJavaMojo.doExec (ExecJavaMojo.java:364)
    at org.codehaus.mojo.exec.ExecJavaMojo.lambda$execute$0 (ExecJavaMojo.java:286)
    at java.lang.Thread.run (Thread.java:1583)

But I checked source code of jooq-jackson-extensions, it already added com.fasterxml.jackson.datatype.jsr310.JavaTimeModule to objectMapper, I don't know why it doesn't work: https://github.com/jOOQ/jOOQ/blob/31839ce5fc302173398e41e40a5e6df3cbd8d5c5/jOOQ-jackson-extensions/src/main/java/org/jooq/jackson/extensions/converters/AbstractToJacksonConverter.java#L65


Solution

  • There are 2 issues at play here.

    A flawed implementation of table valued function code generation

    First off, there seems to be a bug in the jOOQ 3.20.0 code generator, which I've described here:

    The bug is a flawed implementation of #7406 in jOOQ 3.20.0 (table valued functions using SETOF my_type return signature producing TableImpl<MyTypeRecord> classes)

    The table valued function should inherit all the converters and bindings of the returned table or UDT type. This currently isn't the case, so while your Dressing UDT declares DRESSING.ADDRESS to be your Address type via <jsonConverter>, the table valued function still fetches JSONB values. You can work around this by including merge_person.address in the converter specification of your code generator configuration.

    DefaultConverterProvider doesn't work with JavaTimeModule

    Secondly, the Converter not being applied to the returned record, you tried to work around the issue by trying to apply automatic conversion when you call:

    d.get(Dressing.ADDRESS, Address.class)
    

    This exposes the problem with the JavaTimeModule not being loaded, because that call doesn't go by the generated converter (which is absent, see above), but by the DefaultConverterProvider, which isn't aware of this module. That's probably a bug as well: