Adopt Android build on the JDK11 (macOS)

🇺🇦 Eugen Martynov
3 min readAug 18, 2019

Photo by Jordan Merrick on Unsplash

UPD: Most probably this article is not relevant anymore. The tooling involved and you don’t need to do anything when you’re on latest Android Studio/AS Plugin and Gradle.

I’m super grateful to the reviewers of this post: Nelson Osacky, Andrey Mischenko and Mike Wolfson. Thank you, gentle people!

Disclaimer: This post is about how to use JDK11 to build an Android app on macOS. I assume similar steps should be taken on other platforms and it should bring you to the same outcome. This post does not cover the why’s, it is simply a how-to guide.

How to install Open JDK11 on Mac:

  1. Using Homebrew
brew tap AdoptOpenJDK/openjdkbrew cask install adoptopenjdk11

2. Using sdkman

sdk install java 11.0.4.hs-adpt

Both ways set also $JAVA_HOME automatically if you had $JAVA_HOME defined. Don’t forget that you should restart the terminal app. You can check the version of java simply running next command:

java -version

You can find about java language features support on Android from the Jake Wharton’s articles “Android’s Java 8 Support” and “Android’s Java 9, 10, 11, and 12 Support”.

JDK9+ has incompatible changes. Your build might fail without some changes especially if you are using data-binding or annotation processors.

Let’s walk through possible changes to get it working.

Firstly, your build will fail if you use an annotation processor that is annotating generated source with javax.annotation.Generated class. It was moved to the separate dependency JSR-269:Pluggable Annotation Processing API. Many annotation processors handle this correctly. For example, Dagger will generate code based on the JDK version. And you will have the next compile error:

error: package javax.annotation.processing does not exist
import javax.annotation.processing.Generated;
^

To fix you simply add next compile only dependency to your project (thanks to Stanislav Parshin):

dependencies {
compileOnly 'com.github.pengrad:jdk9-deps:1.0'
}

The Java EE APIs are no longer contained in the default classpath in Java SE 9. In Java 11 they are completely removed from the JDK.

Some annotation processors and Data Binding are using JAXB for parsing the XML. So you will see the next error for modules that have such dependencies:

java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException

To fix it you have to add next dependencies to each module:

if (project.hasProperty('kapt')) {
kapt 'javax.xml.bind:jaxb-api:2.3.1'
kapt 'com.sun.xml.bind:jaxb-core:2.3.0.1'
kapt 'com.sun.xml.bind:jaxb-impl:2.3.2'
}

annotationProcessor 'javax.xml.bind:jaxb-api:2.3.1'
annotationProcessor 'com.sun.xml.bind:jaxb-core:2.3.0.1'
annotationProcessor 'com.sun.xml.bind:jaxb-impl:2.3.2'

Note: You can remove the check of kapt presence if you use Kotlin already in the module.

Tip: define some generic grade file with common code (for examplecommon-android-config.gradle):

dependencies {
// things need to have build on JDK9+
compileOnly libraries.jdk9Deps

if (project.hasProperty('kapt')) {
kapt libraries.jaxbApi
kapt libraries.jaxbCore
kapt libraries.jaxbImpl
}

annotationProcessor libraries.jaxbApi
annotationProcessor libraries.jaxbCore
annotationProcessor libraries.jaxbImpl
}

And use it in all the required modules:

apply from: "<path>/common-android-config.gradle"

You can use subprojects{} lambda in the root build.gradleto avoid repetition.

If you use jacoco as code coverage tool then you will face an error about missed classes, like:

java.lang.ClassNotFoundException: jdk.internal.reflect.GeneratedSerializationConstructorAccessor1

To fix it you have to instruct jacoco to exclude such classes:

testOptions {
unitTests {
all {
jacoco {
excludes = ['jdk.internal.*']
}
}
}

Almost the end, if your code (for example in tests) has hardcoded formatted strings you might have issues (for example failing tests) — the JDK9 has changed the formatting of numbers and currencies. So you have to rewrite code to get it working correctly again.

Finally, Android Studio doesn’t support JDK9+. If you try to change JAVA_HOME for the project in Android Studio to JDK9+ then you will get the error:

Path is not valid JDK8 home

Follow https://issuetracker.google.com/issues/139093669 ticket to be notified when it is implemented. This means you will have two gradle daemons if you build your project from command and Android Studio (you will have more memory consumed).

Phew, It was a long read! Follow me on twitter if you want to engage more conversations around such topics.

I assume it will work similarly with any other JDK9+ (9, 10 and 12) also.

Sign up to discover human stories that deepen your understanding of the world.

🇺🇦 Eugen Martynov
🇺🇦 Eugen Martynov

Written by 🇺🇦 Eugen Martynov

Stand with Ukraine! The loving XP husband and freelance Android/Kotlin engineer.

Responses (2)

Write a response

I was searching for the solution to something today and this article came up. I was super excited to see my name as a reviewer.
I probably should have read it closer, so I didn’t need to come back and re-read it ;-).
Thanks for writing it actually…

1

Hi, thank you for this article, I have just something to add if the command to install jdk11 via Brew won't work, use that instead :
brew install --cask adoptopenjdk11