There has been a lot of people asking for a Java/OpenJDK update in the Android Convenience Image for awhile now. AdoptOpenJDK has a great blog post explaining why they’re moving to Java v11 as their default as well. You can find that here. Last month I posted a GitHub Issue discussing this change for August 2020, maybe sooner in July. Considering we’re already in July, we’re going to stick with an August date for this change, updating the image August 17th.
Testing this change
While not available today, we’ll have images you can use to test Android and OpenJDK v11 very soon. This will be our staging images though so my suggestion is to simply use them to test your CI builds for Java v11 support, not as production images to stay on forever.
Stay tuned to this post (there’s a dropdown to “watch” this topic below) or the GitHub Issue to see when these staging images are available.
Avoiding this Change
We will not be running multiple versions of the Android image so you can’t really avoid it long term. Java 8 support for many tools is actively being dropped so this change is going to be needed for many Android ecosystem tools. If by August 17th you are still not ready for this change, you could pin the specific Android image you are using, thus preventing the version of Java from being changed out from under you. Keep in mind, that freezes your image meaning there’ll be no updates at all to it. You can learn more about pinning an image here.
Testing images are now available for this change. Instead of using the circleci Docker Hub namespace that you would normally use for an image, you need to use ccistaging. For example:
Normal image with Java v8
Testing image with Java v11
circleci/android:api-30
ccistaging/android:api-30
circleci/android:api-29-node
ccistaging/android:api-29-node
circleci/android:api-28-ndk
ccistaging/android:api-28-ndk
The Changes
The main change is a simple but significant one. The version of Java used has switched from v8 to v11. It’s useful to make sure your build pipeline still works the same (if not better) with this major Java version change. Java v11 is the next LTS version after v8 and now has complete support from Android Studio, which is why it was chosen.
We now install sdkmanager and related via Android’s Command-Line Tools package instead of the deprecated SDK Tools package.
Reporting
If you run into issues with these testing images, please report them here or on this GitHub Issue.
Information that might help, curated from the CircleCI Community.
UseCGroupMemoryLimitForHeap
If you’re running into an error with UseCGroupMemoryLimitForHeap, this is because this was an experimental flag that was dropped in Java v10. The new Android images use Java v11 and thus don’t support this. You can use -XX:+UseContainerSupport instead.
JAXB
JAXB is not included with JDK 11, so your project has dependencies on the JAXB API or tools, you may need to include them yourself.
Robolectric
Someone has said that Robolectric doesn’t work with version <= 4.2.1. They recently released Robolectric 4.4 which officially includes support for Java v11 (and Java v13 for that matter).
SDKManager Binary
It looks like some people were calling sdkmanager using the full path $ANDROID_HOME/tools/bin/sdkmanager. The preferred method is to just call the binary itself sdkmanager.
This is especially relevant if you get an error like this:
Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema
at com.android.repository.api.SchemaModule$SchemaModuleVersion.<init>(SchemaModule.java:156)
at com.android.repository.api.SchemaModule.<init>(SchemaModule.java:75)
at com.android.sdklib.repository.AndroidSdkHandler.<clinit>(AndroidSdkHandler.java:81)
at com.android.sdklib.tool.sdkmanager.SdkManagerCli.main(SdkManagerCli.java:73)
at com.android.sdklib.tool.sdkmanager.SdkManagerCli.main(SdkManagerCli.java:48)
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.annotation.XmlSchema
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
... 5 more
Sticking with the old image
You can use the old image by switching your config from specifying the SHA hash of the image you were using instead of the tag. We don’t recommend sticking with the old Java v8 based images if you can avoid it. When pinning an image via a hash, they’re no longer supported thus won’t receive any updates. This can be done as a temporary measure. Information on how to do this can be found here.
Android API 29 digest: circleci/android@sha256:b6646fdf7457f61825526e7bfce364d8e533da6ceb1cdb98e371e94348ecc834
Android API 28 digest: circleci/android@sha256:061e2535826cc3fe4c4a440e716bf06c36c80401ee635c339c6803b3e427ebb3
Please do better about communicating potentially breaking changes like this. Two of our developers lost an entire day tracking down why our test suite was failing randomly.
An email or some other explicit notification would have been very helpful. I doubt most people are checking these discussion boards or the CircleCI GitHub issues on a regular basis.
This is a bad idea, since Android DataBinding (being part of build-tools) is internally using JAXB even with latest Gradle Plugin. I had a hard time figuring out why my project builds locally on Java 8 but refuses to build on Java 11.
My project was runing fine and I just got this without any change, this is related to accepting the android licenses with ${ANDROID_HOME}/tools/bin/sdkmanager --licenses.
Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema
at com.android.repository.api.SchemaModule$SchemaModuleVersion.<init>(SchemaModule.java:156)
at com.android.repository.api.SchemaModule.<init>(SchemaModule.java:75)
at com.android.sdklib.repository.AndroidSdkHandler.<clinit>(AndroidSdkHandler.java:81)
at com.android.sdklib.tool.sdkmanager.SdkManagerCli.main(SdkManagerCli.java:73)
at com.android.sdklib.tool.sdkmanager.SdkManagerCli.main(SdkManagerCli.java:48)
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.annotation.XmlSchema
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
... 5 more
This was extremely poorly communicated. We had no notice of this breaking change occurring. Spent way too much time figuring out what was happening till I came across this discussion. Disappointing to say the least.
@aneesh We totally understand. We’re working now on making sure these are communicated better in the future via emails and social media. Is there anywhere else you’d like to see an update that would help?
A banner in the web app for the pipeline/workflow/job pages would have been nice. Especially after the change was made. Day to day, that’s probably the only CircleCi content most devs look at.