Skip to content

Commit cd93a94

Browse files
bigdazclaude
andauthored
Upgrade Jackson to 2.18.8 and drop jackson-module-kotlin (#218)
## What Upgrades the Jackson BOM from **2.14.2 → 2.18.8** to fix the outstanding `jackson-core` / `jackson-databind` CVEs, and removes the `jackson-module-kotlin` dependency that was the real blocker to upgrading. This is a clean, minimal alternative to #215 — it fixes the same CVEs without the test failures that #215 hit on older Gradle versions. | Package | ID | Fixed | |---|---|---| | jackson-core | CVE-2025-52999 | ✅ | | jackson-core | GHSA-72hv-8253-57qq | ✅ | | jackson-databind | CVE-2026-54512 | ✅ | | jackson-databind | CVE-2026-54513 | ✅ | | jackson-databind | CVE-2026-54514 | ✅ | ## Why the previous approach failed on old Gradle `jackson-module-kotlin` ≥ 2.13 calls a **Kotlin 1.5** reflection API (`KClass.isValue()`) during introspection. Because the module excludes the Kotlin stdlib and relies on the Kotlin bundled inside Gradle at runtime, the plugin failed on Gradle **5.2–7.2** (which bundle Kotlin 1.3/1.4) with: ``` Failed to notify build listener. > 'boolean kotlin.reflect.KClass.isValue()' ``` That — not the multi-release jar — was the cause of the old-Gradle failures in #215. (This is why the module was originally pinned to `2.12.3` "because higher versions depend upon Kotlin 1.5".) ## The fix - **Drop `jackson-module-kotlin` entirely.** It is only needed for *deserialization*; this plugin only ever *serializes* (`writeValueAsString`), and Jackson's default bean serializer handles the Kotlin `data class`es via their generated getters. `JacksonJsonSerializer` now uses a plain `JsonMapper`. - **Strip `META-INF/versions/**` from the shaded jar.** Jackson 2.15+ is a multi-release jar with JDK 11/17/21-optimized classes; older Gradle's bundled ASM can't read those newer class file versions when instrumenting the plugin classpath ([gradle/gradle#24390](gradle/gradle#24390)) and fails with *"Unsupported class file major version"*. The Java 8 base classes work everywhere. Stripping all versioned entries (rather than just 17/21) is robust against future JDK-specific variants. The `com.gradleup.shadow` migration this depends on already landed on `main` in #217. ## Verification Ran the functional test suite locally against previously-failing combinations: - ✅ Full `:plugin-test:test` on **Gradle 6.9.4 / JDK 11** and **7.1.1 / JDK 11** (both previously failed with the Kotlin error) — pass. - ✅ **Gradle 5.2.1 / 5.6.4 on JDK 8** — no `NoSuchMethodError` and no *"Unsupported class file major version"* (the shaded jar loads and the plugin runs). - ✅ JSON-schema validation and exact property-name assertions in the suite confirm serialized output is unchanged without the Kotlin module. Closes #215 (supersedes). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 8dfe77e commit cd93a94

3 files changed

Lines changed: 12 additions & 15 deletions

File tree

gradle/libs.versions.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ spock = "2.4-groovy-3.0"
33
kotlin = "1.8.10"
44

55
[libraries]
6-
jackson-platform = { group = "com.fasterxml.jackson", name = "jackson-bom", version = "2.14.2" } # Cannot upgrade to 2.15.x, due to https://github.com/gradle/gradle/issues/24390
6+
jackson-platform = { group = "com.fasterxml.jackson", name = "jackson-bom", version = "2.18.8" }
77
jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind" }
88
jackson-parameter-names = { group = "com.fasterxml.jackson.module", name = "jackson-module-parameter-names" }
9-
jackson-kotlin = { group = "com.fasterxml.jackson.module", name = "jackson-module-kotlin" }
109

1110
apache-commons-io = { group = "commons-io", name = "commons-io", version = "2.21.0" }
1211
apache-log4j-core = { group = "org.apache.logging.log4j", name = "log4j-core", version = "2.25.4" }

plugin/build.gradle.kts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,6 @@ dependencies {
4646
compileOnly(kotlin("reflect"))
4747
shadowImplementation(platform(libs.jackson.platform))
4848
shadowImplementation(libs.jackson.databind)
49-
shadowImplementation(libs.jackson.kotlin) {
50-
version {
51-
strictly("2.12.3")
52-
}
53-
exclude(group = "org.jetbrains.kotlin")
54-
because("kotlin std lib is bundled with Gradle. 2.12.3 because higher versions depend upon Kotlin 1.5")
55-
}
5649
shadowImplementation(libs.github.packageurl)
5750

5851
// Use JUnit Jupiter for testing.
@@ -92,6 +85,12 @@ tasks.withType<PluginUnderTestMetadata>().configureEach {
9285

9386
val shadowJarTask = tasks.named<ShadowJar>("shadowJar") {
9487
archiveClassifier = ""
88+
// Strip multi-release class files (Jackson ships JDK 11/17/21 optimized variants under
89+
// META-INF/versions). Older Gradle versions bundle an ASM that cannot read these newer
90+
// class file versions when they instrument the plugin classpath, failing with
91+
// "Unsupported class file major version". The Java 8 base classes work on all supported
92+
// Gradle versions. See https://github.com/gradle/gradle/issues/24390
93+
exclude("META-INF/versions/**")
9594
configurations = listOf(shadowImplementation)
9695
val projectGroup = project.group
9796
doFirst {

plugin/src/main/kotlin/org/gradle/dependencygraph/util/JacksonJsonSerializer.kt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
package org.gradle.dependencygraph.util
22

3-
import com.fasterxml.jackson.module.kotlin.jsonMapper
4-
import com.fasterxml.jackson.module.kotlin.kotlinModule
3+
import com.fasterxml.jackson.annotation.JsonInclude
4+
import com.fasterxml.jackson.databind.json.JsonMapper
55

66
object JacksonJsonSerializer {
7-
private val mapper = jsonMapper {
8-
serializationInclusion(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL)
9-
addModule(kotlinModule())
10-
}
7+
private val mapper = JsonMapper.builder()
8+
.serializationInclusion(JsonInclude.Include.NON_NULL)
9+
.build()
1110

1211
fun serializeToJson(dependencyGraph: Any): String {
1312
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(dependencyGraph)

0 commit comments

Comments
 (0)