Issue
I'm attempting to use the new desugaring features in AGP, however I am getting the following error when trying to use ConcurrentHashMap.newKeySet()
in my app:
10-23 21:17:49.471 5023-5023/uk.org.mattford.scoutlink E/AndroidRuntime: FATAL EXCEPTION: main
Process: uk.org.mattford.scoutlink, PID: 5023
java.lang.NoSuchMethodError: No static method newKeySet()Lj$/util/concurrent/ConcurrentHashMap$KeySetView; in class Lj$/util/concurrent/ConcurrentHashMap; or its super classes (declaration of 'j$.util.concurrent.ConcurrentHashMap' appears in /data/app/uk.org.mattford.scoutlink-1/base.apk:classes3.dex)
at org.pircbotx.hooks.managers.ThreadedListenerManager.<init>(ThreadedListenerManager.java:49)
at org.pircbotx.Configuration$Builder.getListenerManager(Configuration.java:884)
at org.pircbotx.Configuration$Builder.addListener(Configuration.java:726)
at uk.org.mattford.scoutlink.irc.IRCService.connect(IRCService.java:143)
at uk.org.mattford.scoutlink.irc.IRCService.onStartCommand(IRCService.java:67)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2864)
at android.app.ActivityThread.access$2100(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1376)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
I have the following in my top level build.gradle
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath 'com.google.gms:google-services:4.3.4'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.3.0'
}
}
allprojects {
repositories {
google()
jcenter()
maven {
url 'https://oss.sonatype.org/content/repositories/snapshots'
}
}
}
and in my module build-gradle
:
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'
android {
compileSdkVersion 29
buildToolsVersion '29.0.3'
defaultConfig {
applicationId "uk.org.mattford.scoutlink"
minSdkVersion 16
targetSdkVersion 29
multiDexEnabled true
}
buildTypes {
release {}
}
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/license.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/notice.txt'
exclude 'META-INF/ASL2.0'
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
productFlavors {
}
buildFeatures {
viewBinding = true
}
}
dependencies {
implementation 'org.slf4j:slf4j-android:1.7.30'
implementation 'org.pircbotx:pircbotx:2.3-SNAPSHOT'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.firebase:firebase-analytics:17.6.0'
implementation 'com.google.firebase:firebase-crashlytics:17.2.2'
implementation 'com.google.android.material:material:1.2.1'
implementation "androidx.room:room-runtime:2.2.5"
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation "androidx.lifecycle:lifecycle-viewmodel:2.2.0"
annotationProcessor "androidx.room:room-compiler:2.2.5"
implementation 'androidx.multidex:multidex:2.0.1'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.10'
}
Looking at the APK analyser. I can see that j$.util.concurrent.ConcurrentHashMap
is defined in classes3.dex
but does not include the newKeySet
method. However j$.util.concurrent.ConcurrentHashMap
is also defined in classes4.dex
and does have this method!
The ConcurrentHashMap.newKeySet
call I am trying to work around is in the pircbotx dependency. However I have put a call to this method in my Application's onCreate
method and this also crashes the app.
Thanks in advance for any help. I've been at this for hours now to no avail.
Solution
This turned out to be a "bug" in D8, it turns out that although the following 3 methods are listed in the docs (https://developer.android.com/studio/write/java8-support-table) as supported, they are not actually currently supported.
This has been raised a feature request but according to the D8 team it is unlikely they will be looked at this quarter. (full discussion of the issue here: https://issuetracker.google.com/171666278)
public ConcurrentHashMap.KeySetView keySet(Object mappedValue)
public static ConcurrentHashMap.KeySetView newKeySet()
public static ConcurrentHashMap.KeySetView newKeySet(int initialCapacity)
Answered By - Matt
Answer Checked By - David Marino (JavaFixing Volunteer)