FasterXML / jackson-module-kotlin

Module that adds support for serialization/deserialization of Kotlin (http://kotlinlang.org) classes and data classes.
Apache License 2.0
1.12k stars 175 forks source link

`NoSuchMethodError` for `com.fasterxml.jackson.module.kotlin.jacksonObjectMapper` after upgrading to 2.17.0 #775

Closed erdi closed 4 months ago

erdi commented 6 months ago

Search before asking

Describe the bug

Calling jacksonObjectMapper() after importing com.fasterxml.jackson.module.kotlin.jacksonObjectMapper after upgrading to 2.17.0 throws

Caused by: java.lang.NoSuchMethodError: 'com.fasterxml.jackson.databind.ObjectMapper com.fasterxml.jackson.module.kotlin.ExtensionsKt.jacksonObjectMapper$default(kotlin.jvm.functions.Function1, int, java.lang.Object)'

I believe that's related to https://github.com/FasterXML/jackson-module-kotlin/commit/0dbe80282dba1c99dbe1ab22981641bea2969148. By the looks of things there's @JvmOverloads and the new arg is defaulted so this should just work, shouldn't it?

FWIW, I've also tried jacksonObjectMapper {} but got

Caused by: java.lang.NoSuchMethodError: 'com.fasterxml.jackson.databind.ObjectMapper com.fasterxml.jackson.module.kotlin.ExtensionsKt.jacksonObjectMapper(kotlin.jvm.functions.Function1)'

To Reproduce

jacksonObjectMapper()

Expected behavior

No response

Versions

Kotlin: 1.9.20 Jackson-module-kotlin: 2.17.0 Jackson-databind: 2.17.0

Additional context

Not sure if that matters at all but the method in question is called from a field initializer in a companion object of a Gradle plugin implemented in kotlin.

erdi commented 6 months ago

FYI, ObjectMapper().registerModule(kotlinModule()) where kotlinModule is imported as com.fasterxml.jackson.module.kotlin.kotlinModule seems to work. kotlinModule does not carry @JvmOverloads so maybe that's related?

k163377 commented 6 months ago

From the error message, it looks like you are running code compiled with 2.17 on a version less than 2.17. Can you confirm which version is being used at runtime? Or more information is needed.

Dogacel commented 5 months ago

I am having the same issue, I am almost certain our runtime versions are up-to-date and 2.17.

k163377 commented 5 months ago

Please attach reproducible code.

Also, please check the com.fasterxml.jackson.module.kotlin.PackageVersion at runtime. As mentioned above, the version of KotlinModule may have been overwritten at runtime. If not, you should get 2.17.x.

Dogacel commented 5 months ago

Sorry I can't because it is company code.

However, I figured it out. Turns out my dependency tree was different in runtime and compile time somehow. The reason why I never realized this is that spring gradle plugin enforces a certain version of kotlin and it basically overrides everything that you specify in dependencies block. The only solution is to add the following,

configurations.all {
  resolutionStrategy.eachDependency { details ->
    if (details.requested.group.startsWith("com.fasterxml.jackson")) {
      details.useVersion("2.17.0")
    }
  }
}
k163377 commented 5 months ago

Thanks for the verification. Anyway, it seems that there is no problem with jackson-module-kotlin, so this issue is closed.

cowtowncoder commented 5 months ago

And fwtw, Jackson 2.17.1 was just released today. Probably won't change behavior here but just in case, upgrade strongly recommended (from 2.17.0).

be-hase commented 4 months ago

@k163377 Did jackson intentionally make the compatibility loss from version 2.17?

Spring boot users often tend to use BOM to fix version. (using dependency-management-plugin, gradle constraints, etc...)

The latest spring boot BOM is still jackson 2.15.4, so I think there are many cases in the JVM community where code compiled with 2.17.x is used in older jackson environments.

If there is a reason for the loss of compatibility, we should accept, but if the loss of compatibility is unintentional?

The reproduction code is available here. https://github.com/be-hase/jackson-issue-202405

k163377 commented 4 months ago

@be-hase I was mistaken on this issue. I assumed that Kotlin would prioritise the use of non-default functions, but unfortunately this is not the case. https://youtrack.jetbrains.com/issue/KT-17300

As you say, this was unintentionally breaking compatibility.

I will look into fixing this over the weekend if possible.

be-hase commented 4 months ago

Thanks.

I did a little research and it doesn't look like there is a good way to do it... The only way might be to write the overload by hand.

https://medium.com/@yi.lu_55329/is-kotlin-default-arguments-a-solution-of-binary-backward-compatibility-374d2c9214d4

k163377 commented 4 months ago

This will be fixed in the next release.

be-hase commented 4 months ago

thanks :)