spring-cloud / spring-cloud-function

Apache License 2.0
1.03k stars 614 forks source link

4.1.3 Fails to convert message payload (json) to Kotlin data types #1158

Open dnijssen opened 1 month ago

dnijssen commented 1 month ago

Describe the bug In https://github.com/spring-cloud/spring-cloud-function/issues/1148 changes were made to construct a new ObjectMapper instance instead of using the ObjectMapper from application context. This causes many necessary modules are not registered anymore.

For example I know get the following exception when trying to access a Message<DTO> (were DTO is a data class from Kotlin) payload (message.payload) in a Spring Cloud Function using Spring Cloud Stream Binders (with a Message<>) ;

java.lang.ClassCastException: class java.lang.String cannot be cast to class org.example.DTO (java.lang.String is in module java.base of loader 'bootstrap'; org.example.DTO is in unnamed module of loader 'app')

But the underlying message/stacktrace in the JacksonMapper is as followed:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `org.example.DTO` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 3, column: 15]

Also as a Spring user I would expect the common ObjectMapper so it is used through out various components of Spring would just be used by Spring Cloud Function as well.

Maybe instead of doing new ObjectMapper() which constructs a very "basic" jackson ObjectMapper instance you can use the Jackson2ObjectMapperBuilder instead, which can (and is already by Spring Framework) customized in various ways. E.g. to check if Kotlin is present and if so add the missing KotlinModule.

rogervinas commented 1 month ago

Indeed JsonMapperConfiguration 4.1.2 vs 4.1.3 (diff here) makes CompositeMessageConverterFactory's json mapper registered modules differ:

4.1.2:

0 = "com.fasterxml.jackson.datatype.jdk8.Jdk8Module"
1 = "jackson-module-parameter-names"
2 = "jackson-datatype-jsr310"
3 = "com.fasterxml.jackson.module.kotlin.KotlinModule"
4 = "org.springframework.boot.jackson.JsonMixinModule"
5 = "org.springframework.boot.jackson.JsonComponentModule"

4.1.3:

0 = "jackson-datatype-jsr310"

So deserialization to kotlin does not work anymore. I have a sample using data classes and Bump spring-cloud-dependencies from 2023.0.2 to 2023.0.3 is failing

I've found other related issues here:

And a workaround here https://github.com/spring-cloud/spring-cloud-function/issues/1159#issuecomment-2225239377 🚀