Fix Duplicate Hamcrest Classes in Android Gradle
Resolve duplicate class errors like org.hamcrest.BaseDescription in Android Gradle projects when adding json-simple. Learn excludes, resolutionStrategy force, and substitution for Gradle 8.3 and Android Studio Otter 2.
How to resolve duplicate Hamcrest class errors in Android Gradle project when adding json-simple dependency?
I’m using the latest stable Android Studio (Otter 2) with Gradle 8.3. My project includes a library module shared between an Android app and a Jakarta-based server, so I selected com.googlecode.json-simple:json-simple for JSON parsing.
Adding this dependency (either in the library module or as runtimeOnly) triggers multiple duplicate class errors for Hamcrest classes from hamcrest-core-1.1.jar (org.hamcrest:hamcrest-core:1.1) and junit-4.10.jar (junit:junit:4.10):
Duplicate class org.hamcrest.BaseDescription found in modules hamcrest-core-1.1.jar -> hamcrest-core-1.1 (org.hamcrest:hamcrest-core:1.1) and junit-4.10.jar -> junit-4.10 (junit:junit:4.10)
Duplicate class org.hamcrest.BaseMatcher found in modules hamcrest-core-1.1.jar -> hamcrest-core-1.1 (org.hamcrest:hamcrest-core:1.1) and junit-4.10.jar -> junit-4.10 (junit:junit:4.10)
Duplicate class org.hamcrest.CoreMatchers found in modules hamcrest-core-1.1.jar -> hamcrest-core-1.1 (org.hamcrest:hamcrest-core:1.1) and junit-4.10.jar -> junit-4.10 (junit:junit:4.10)
(and similar errors for other org.hamcrest classes like Description, Matcher, StringDescription, AllOf, AnyOf, etc.)
Attempts to exclude JUnit using:
configurations {
compile.exclude group: "junit", module: "junit"
}
failed (either no effect or syntax errors), whether placed in the android block or at the top level.
What is the correct way to resolve these duplicate class conflicts in modern Gradle/Android Studio?
Duplicate class errors in your android gradle project pop up because json-simple bundles an ancient junit 4.10 that drags in hamcrest-core 1.1, clashing with any other hamcrest or junit on the classpath—like during dexing in Android Studio Otter 2 with Gradle 8.3. The fix? Exclude the offending junit (or hamcrest) directly from the json-simple dependency in your library module’s build.gradle, like this: runtimeOnly('com.googlecode.json-simple:json-simple:1.1.1') { exclude group: 'junit' }. If that doesn’t cut it for your shared Android/Jakarta setup, force a unified hamcrest version via resolutionStrategy—keeps things clean without breaking tests.
Contents
- Understanding Duplicate Class Errors in Android Gradle
- Why json-simple Triggers Hamcrest Duplicates
- Fix 1: Exclude JUnit or Hamcrest from json-simple
- Fix 2: Force a Single Hamcrest Version
- Fix 3: Use Dependency Substitution
- Verify Your Fixes and Prevent Regressions
- Sources
- Conclusion
Understanding Duplicate Class Errors in Android Gradle
Ever hit a wall where your android gradle build screams about duplicate class issues right after adding a seemingly innocent dependency? You’re not alone. In Gradle 8.3 with Android Studio Otter 2, these errors—especially for org.hamcrest classes like BaseDescription or CoreMatchers—crop up during APK dexing or R8 merging.
The JVM (or ART in Android) hates ambiguity: two jars with the same class? Pick one at random, and boom—non-deterministic crashes or subtle bugs. Gradle detects this proactively now, throwing duplicate class found errors to save you from runtime pain. For library modules shared across Android apps and Jakarta servers, it’s extra tricky since runtimeOnly deps like json-simple leak into both worlds.
Why your old exclude attempt flopped? That configurations { compile.exclude ... } syntax is ancient—pre-Gradle 4 vibes. Modern setups demand per-dependency excludes or resolution strategies. Stick around; we’ll nail this.
Why json-simple Triggers Hamcrest Duplicates
json-simple looks lightweight for JSON parsing, right? Wrong—it’s a time bomb. Version 1.1.1 (or whatever you’re on) transitively pulls junit:junit:4.10, which bundles hamcrest-core:1.1 right inside. Add any other dep with newer hamcrest (common in AndroidX tests or plugins), and kaboom: java duplicate class for BaseMatcher, StringDescription, the works.
Stack Overflow users nailed it: json-simple’s junit is the culprit, not your app code. In shared libs, this hits harder—server-side Jakarta might tolerate it, but Android’s multidex/R8? No mercy. Pro tip: ./gradlew app:dependencies --configuration runtimeClasspath (swap “app” for your lib module) reveals the duplicates lurking.
And hamcrest? It’s a matcher lib for tests, but junit 4.10 embeds it to avoid extra pulls. Fast-forward to 2026: everything’s on hamcrest 2.x or dropped it. Your error log spells it out—hamcrest-core-1.1.jar vs. junit-4.10.jar duking it out.
Fix 1: Exclude JUnit or Hamcrest from json-simple
Hands down, the cleanest fix for android duplicate class woes. Target json-simple directly in your library module’s build.gradle. Ditch global configs; they’re blunt instruments.
Add this under dependencies:
runtimeOnly('com.googlecode.json-simple:json-simple:1.1.1') {
exclude group: 'junit', module: 'junit'
}
Or, if junit exclude breaks something quirky:
runtimeOnly('com.googlecode.json-simple:json-simple:1.1.1') {
exclude group: 'org.hamcrest', module: 'hamcrest-core'
}
This Stack Overflow thread confirms it works like a charm—hamcrest stays unified from elsewhere, json-simple parses without the baggage. Sync Gradle, clean/rebuild. For implementation scope (if not runtimeOnly), same deal.
Why per-dependency? Global excludes risk nuking legit test junit. In your shared lib? Perfect—Android builds dodge it, Jakarta ignores the test dep anyway.
Quick win, but what if excludes miss a transitive?
Fix 2: Force a Single Hamcrest Version
Excludes not enough? Override the classpath entirely. Drop this in your library module’s build.gradle, outside android{}:
configurations.all {
resolutionStrategy {
force 'org.hamcrest:hamcrest-core:1.3'
}
}
Bumps everything to 1.3, silencing duplicate class found in modules noise. Tested in Gradle 7+ Android projects—even json-simple’s 1.1 bends the knee.
For bleeding-edge (hamcrest 2.2), swap 1.3 for 2.2. But careful: older junit might whine. Your setup? 1.3 plays nice with junit 4.10 relics.
Reddit libgdx folks swear by combining with explicit hamcrest add if needed: implementation 'org.hamcrest:hamcrest-core:1.3'. Boom— no duplicates, shared lib bliss.
Fix 3: Use Dependency Substitution
Gradle 8.3’s secret weapon for stubborn error duplicate class. Swap json-simple’s bad hamcrest for a good one project-wide:
configurations.all {
resolutionStrategy {
dependencySubstitution {
substitute module('org.hamcrest:hamcrest-core:1.1')
.using(module('org.hamcrest:hamcrest-core:1.3'))
}
}
}
AndroidBugFix details how this unifies versions without excludes. Add android.useAndroidX=true and android.enableJetifier=true to gradle.properties for extra polish.
For your Jakarta server share? Substitution scopes to the module, no ripple effects. Another SO post used it post-Gradle update—mirrors your Otter 2/8.3 combo.
Pick your poison: excludes for precision, force/substitution for hammer-time.
Verify Your Fixes and Prevent Regressions
Fixed? Don’t trust blindly. Run ./gradlew :yourlib:dependencies --configuration runtimeClasspath | grep -i hamcrest—one version only, victory. Build APK, test JSON parsing. Server-side? gradle build sans Android plugins.
Prevent future pain: Pin json-simple to 1.1.1, monitor with Gradle dependency lockfiles. Ditch json-simple long-term? Gson or Jackson slimmer, no baggage.
GitHub issue trackers echo: ./gradlew dependencies is your debug buddy. In multi-module? Apply fixes to the lib, propagate via :app:assembleDebug.
Still stuck? ./gradlew build --stacktrace + check transitive deps. You’ve got this.
Sources
- Duplicate class org.hamcrest - Stack Overflow
- Error JSON.simple: java.util.zip.ZipException: duplicate entry: org/hamcrest/BaseDescription.class - Stack Overflow
- Duplicate class org.hamcrest.BaseDescription found in modules jetified-hamcrest-core-1.3.jar - Stack Overflow
- How to fix dependency resolution errors? - Reddit
- Duplicate class in build.gradle file - AndroidBugFix
- Duplicate Hamcrest Class Errors When Runtime Dependsancy On Json-Simple Added - Stack Overflow
- Dependency build errors “Duplicate class org.hamcrest…” in Android Studio project, for Espresso UI Tests - GitHub
- Duplicate Hamcrest and JUnit classes after updating Gradle and Android Studio to 3.5 - Stack Overflow
Conclusion
Android gradle duplicate class headaches from json-simple vanish with targeted excludes on its junit dep—fastest path for your shared lib. If conflicts linger, force hamcrest 1.3 or substitute via resolutionStrategy; both shine in Gradle 8.3. Verify with dependency reports, swap to modern JSON libs eventually, and your Android/Jakarta builds stay smooth. No more dex drama.