Skip to content

Repair NoSuchFieldError on Jackson 2.20+, remove javax.activation, upgrade dependencies and tests - #78

Open
sbailliez wants to merge 6 commits into
uploadcare:masterfrom
sbailliez:upgrade-dependencies
Open

sbailliez wants to merge 6 commits into
uploadcare:masterfrom
sbailliez:upgrade-dependencies

Conversation

@sbailliez

@sbailliez sbailliez commented Oct 24, 2026 •

Copy link
Copy Markdown

Problem

Client reads PropertyNamingStrategy.SNAKE_CASE. Jackson deprecated that field in 2.12 and removed it in 2.20. With the released 3.5.3 jar and jackson-databind 2.20 or later on the classpath, creating a Client fails:

Exception in thread "main" java.lang.NoSuchFieldError: SNAKE_CASE
	at com.uploadcare.api.Client.<init>(Client.java:137)
	at com.uploadcare.api.Client.<init>(Client.java:85)
	at com.uploadcare.api.Client.demoClient(Client.java:152)

Changes

  1. Client uses PropertyNamingStrategies.SNAKE_CASE. It exists since Jackson 2.12 and gives the same naming. No public API change.
  2. Gradle wrapper: 8.2 -> 8.14.6, the newest 8.x. The README now says 8.14.6. Gradle 9 is not part of this change. feat: upgrade to a more recent JDK (21 or higher) #73 moves the build to Gradle 9.
  3. Dependencies:
Dependency Old New
httpclient 4.5.13 4.5.14
httpmime 4.5.13 4.5.14
jackson-databind 2.16.2 2.21.8 (2.21 is the long-term support line of Jackson)
commons-codec 1.10 1.23.0
commons-io 2.7 2.22.0
junit (test) 4.13.1 replaced by JUnit Jupiter 6.1.3 (junit-bom)
mockito-all (test) 1.10.19 replaced by mockito-core 5.24.0 and mockito-junit-jupiter 5.24.0
foojay-resolver-convention (settings plugin) none 1.0.0 (new)
javax.activation 1.2.0 removed (see below)

Notes:

  • mockito-all has no release after 1.10.19, so the tests use mockito-core. Mockito 4 removed org.mockito.Matchers, so FileUploaderTest uses ArgumentMatchers and an ArgumentMatcher.
  • httpclient 4.5.14 is the last 4.x release. httpclient5 has a different API, so it is not part of this change.
  • Jackson 3 has new package names and needs Java 17, so this stays on Jackson 2.
  • The library still targets Java 7 (class files are still major version 51, see below). All new runtime dependencies need Java 8, as jackson-databind 2.16.2 did before.
  • The versions of the GitHub Actions are not changed. feat: upgrade to a more recent JDK (21 or higher) #73 covers them.

Jakarta EE (issue #50)

RequestHelper.getMimeType used javax.activation.MimetypesFileTypeMap. With a Jakarta activation jar on the classpath, this can fail with IllegalAccessError in MimetypesFileTypeMap (see #50).

getMimeType now uses the file name table of the JDK, URLConnection.getFileNameMap(). The signature does not change. The default for an unknown name or a null name is still application/octet-stream (a null name threw an exception before). The com.sun.activation:javax.activation dependency is removed, and nothing else in the library uses javax.activation. The library now has no Java EE or Jakarta EE API dependency.

Behavior difference: the JDK table knows more types than the default table of javax.activation, so some files get a more exact type. The results for common extensions:

File Before, JDK 8 After, JDK 8 Before, JDK 11 After, JDK 11
.png application/octet-stream image/png image/png image/png
.PNG application/octet-stream image/png image/png image/png
.jpg, .jpeg image/jpeg image/jpeg image/jpeg image/jpeg
.gif image/gif image/gif image/gif image/gif
.txt text/plain text/plain text/plain text/plain
.html text/html text/html text/html text/html
.pdf application/octet-stream application/pdf application/octet-stream application/pdf
.zip application/octet-stream application/zip application/octet-stream application/zip
.webp application/octet-stream application/octet-stream application/octet-stream image/webp
.json application/octet-stream application/octet-stream application/octet-stream application/json
.svg application/octet-stream application/octet-stream application/octet-stream image/svg+xml
.mp4 application/octet-stream application/octet-stream application/octet-stream video/mp4
.csv application/octet-stream application/octet-stream application/octet-stream text/csv
.heic application/octet-stream application/octet-stream application/octet-stream application/octet-stream
unknown, no extension application/octet-stream application/octet-stream application/octet-stream application/octet-stream

"Before, JDK 8" is lower than "Before, JDK 11" because on JDK 8 the javax.activation classes of the JDK itself take precedence over the 1.2.0 jar. No type became less exact.

Fixes #50

Tests on JUnit 6

The 4 test classes move from JUnit 4 to JUnit 6 (org.junit.jupiter.api, @BeforeEach, assertThrows). CdnPathBuilderTest uses MockitoExtension with @Mock. FileUploaderTest keeps mock(), because the strict stubs of MockitoExtension reject its second, unstubbed executeQuery call.

JUnit 6 needs Java 17 to run. The published library still targets Java 7:

  • The build uses a JDK 17 toolchain. compileJava uses --release 7. JDK 17 is the newest LTS JDK that supports release 7 (JDK 20 removed it), and it gives a warning that -Xlint:-options hides. compileTestJava uses --release 17.
  • The foojay resolver settings plugin downloads JDK 17 if it is not installed. So ./gradlew build works when Gradle runs on JDK 17 or later.
  • The tests run on JDK 17 by default. -PtestJavaVersion=21 runs them on JDK 21.
  • The Mockito agent loads at test JVM start, as the Mockito documentation advises for Mockito 5.
  • Client.class in the built jar has class file major version 51 (Java 7), as before. The Gradle module metadata has org.gradle.jvm.version: 7. The jar works on JDK 8: Client.demoClient() and RequestHelper.getMimeType("olympia.jpg") run with no error.

CI changes:

  • The build matrix changes from JDK 8 and 11 to JDK 17 and 21, because JUnit 6 cannot run on JDK 8 or 11. Each job runs ./gradlew build -PtestJavaVersion=<matrix JDK>.
  • The snapshot job and the tagged release job run Gradle on JDK 17 in place of JDK 8.
  • build.yml uses pull_request_target, so the run for this PR uses the workflow of master (JDK 8 and 11), not the new matrix. On this PR, that run fails at the Checkout step before the build: actions/checkout refuses to check out fork pull request code from a pull_request_target workflow. This happens for any PR from a fork, and this PR does not change it. On master (JDK 8 and 11), the tests would also fail, because JUnit 6 needs Java 17. The new matrix applies after the merge.

Overlap with draft #73: #73 also moves the tests to JUnit 6 and Mockito 5. But #73 also moves the library itself to Java 21, while this PR keeps the Java 7 target. If #73 merges first, this PR needs a rebase on the test and build files.

Tests

  • ./gradlew build passes with Gradle on Temurin JDK 17 (17.0.21), tests on JDK 17.
  • ./gradlew build -PtestJavaVersion=21 passes with Gradle on Corretto JDK 21 (21.0.12). The compile used the JDK 17 toolchain that the foojay plugin downloaded, and the tests ran on JDK 21.
  • Before the JUnit 6 change, ./gradlew build also passed on Temurin JDK 8 (1.8.0_504) and JDK 11 (11.0.32.1).
  • 11 unit tests ran, 0 failures, 0 skipped: FileTest (1), RequestHelperTest (3), CdnPathBuilderTest (5), FileUploaderTest (2). RequestHelperTest creates a Client and thus covers the Jackson change. The new RequestHelperTest.test_getMimeType covers .png, .jpg, .txt, an unknown extension, no extension and null.
  • No test in the repository calls the live Uploadcare API, so no test with real keys ran.
  • Manual check on Corretto JDK 21: the released 3.5.3 jar with jackson-databind 2.21.8 throws the NoSuchFieldError above. The jar from this branch creates Client.demoClient() with no error.
  • I did not reproduce the exact IllegalAccessError of Provide support for Jakarta EE #50 locally (3.5.3 with jakarta.activation-api 2.1.1, jakarta.activation 2.0.1 or angus-activation 2.0.1 on JDK 11 did not fail). The change removes the cause: the library no longer loads any javax.activation class.

PropertyNamingStrategy.SNAKE_CASE was deprecated in Jackson 2.12 and
removed in Jackson 2.20. With jackson-databind 2.20 or later on the
classpath, creating a Client fails with:

    java.lang.NoSuchFieldError: SNAKE_CASE

PropertyNamingStrategies.SNAKE_CASE exists since Jackson 2.12 and gives
the same naming.
8.14.6 is the newest 8.x release. Gradle 9 needs Java 17 or later to
run Gradle itself, and the CI builds with JDK 8 and 11, so this change
stays on Gradle 8.

The wrapper jar matches the published SHA-256 checksum for 8.14.6.
* httpclient and httpmime: 4.5.13 -> 4.5.14
* jackson-databind: 2.16.2 -> 2.22.4
* commons-codec: 1.10 -> 1.23.0
* commons-io: 2.7 -> 2.22.0
* junit: 4.13.1 -> 4.13.2
* mockito-all 1.10.19 -> mockito-core 4.11.0

mockito-all has no release after 1.10.19. mockito-core 4.11.0 is the
newest release that runs on Java 8. Mockito 5 needs Java 11, and the
CI also builds with JDK 8.

Mockito 4 removed org.mockito.Matchers and takes an ArgumentMatcher in
argThat(), so FileUploaderTest uses ArgumentMatchers and an
ArgumentMatcher in place of a Hamcrest matcher.

javax.activation 1.2.0 is the last release of that artifact. It stays
as is.
@coderabbitai

coderabbitai Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: be935839-a63f-4577-aa14-f768622f452d
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

RequestHelper.getMimeType used javax.activation.MimetypesFileTypeMap.
With a Jakarta activation jar on the classpath, this can fail with
IllegalAccessError in MimetypesFileTypeMap (issue uploadcare#50).

getMimeType now uses the file name table of the JDK,
URLConnection.getFileNameMap(), which exists since Java 1.1. The
signature does not change, and the default for an unknown or null name
is still application/octet-stream.

The JDK table knows more types than the default table of
javax.activation, so some files get a more exact type. For example,
.pdf and .zip now give application/pdf and application/zip in place of
application/octet-stream.

Remove com.sun.activation:javax.activation from the dependencies.
Nothing else in the library uses javax.activation.

Fixes uploadcare#50
@sbailliez sbailliez changed the title Repair NoSuchFieldError on Jackson 2.20+ and upgrade dependencies Repair NoSuchFieldError on Jackson 2.20+, remove javax.activation, upgrade dependencies Oct 24, 2026
* junit 4.13.2 -> JUnit Jupiter 6.1.3 (junit-bom)
* mockito-core 4.11.0 -> 5.24.0, plus mockito-junit-jupiter 5.24.0

JUnit 6 needs Java 17 to run, so the build uses a JDK 17 toolchain.
The library is still compiled with --release 7: JDK 17 is the newest
LTS JDK that can do that (JDK 20 removed release 7). The class files in
the jar stay at major version 51 (Java 7). The tests compile with
--release 17. The foojay resolver plugin downloads JDK 17 when it is
not installed.

The tests run on JDK 17 by default. -PtestJavaVersion=21 runs them on
another JDK. The Mockito agent loads at test JVM start, as the Mockito
documentation advises.

The CI matrix changes from JDK 8 and 11 to JDK 17 and 21, because
JUnit 6 cannot run on JDK 8 or 11. The snapshot and release jobs run
Gradle on JDK 17.

Test changes: org.junit.jupiter.api, @beforeeach, assertThrows in
CdnPathBuilderTest, and MockitoExtension with @mock in
CdnPathBuilderTest.
@sbailliez sbailliez changed the title Repair NoSuchFieldError on Jackson 2.20+, remove javax.activation, upgrade dependencies Repair NoSuchFieldError on Jackson 2.20+, remove javax.activation, upgrade dependencies and tests Oct 24, 2026
Jackson 2.21 is the long-term support line. 2.22 is a feature line.
2.21.8 is the newest 2.21 patch. OSV lists no advisory for it.
The 11 tests pass.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Provide support for Jakarta EE

2 participants