Search code examples
dockersbtplayframework-2.0java-9sbt-native-packager

Running Java 9 application with docker doesn't work - UnsupportedClassVersionError


I changed my application from Java 8 to Java 9. Changed the Windows system environment variable (path) and the JAVA_HOME to Java 9 (jdk-9.0.1).

When running the application in the IDE (IntelliJ) it works fine. It also compiles without problems with sbt. Just running the application with docker doesn't work.

The application seems to be compiled successfully with Java 9 but docker tries to run it with Java 8 (this is what I read from the exception message).

Commands:

sbt docker:publish

docker run --rm -p 9000:9000 eu.gcr.io/the-repository-name/the-image-name:1.0

I get the following error:

Exception in thread "main" java.lang.UnsupportedClassVersionError: 
    Module has been compiled by a more recent version of the 
    Java Runtime (class file version 53.0), this version of the 
    Java Runtime only recognizes class file versions up to 52.0
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
        at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        at play.api.inject.Modules$.locate(Module.scala:119)
        at play.api.inject.guice.GuiceableModule$.loadModules(GuiceInjectorBuilder.scala:276)
        at play.api.inject.guice.GuiceApplicationBuilder$.$anonfun$$lessinit$greater$default$9$1(GuiceApplicationBuilder.scala:30)
        at play.api.inject.guice.GuiceApplicationBuilder.applicationModule(GuiceApplicationBuilder.scala:102)
        at play.api.inject.guice.GuiceBuilder.injector(GuiceInjectorBuilder.scala:185)
        at play.api.inject.guice.GuiceApplicationBuilder.build(GuiceApplicationBuilder.scala:137)
        at play.api.inject.guice.GuiceApplicationLoader.load(GuiceApplicationLoader.scala:21)
        at play.core.server.ProdServerStart$.start(ProdServerStart.scala:51)
        at play.core.server.ProdServerStart$.main(ProdServerStart.scala:25)
        at play.core.server.ProdServerStart.main(ProdServerStart.scala)

What do I have to do, that Docker uses Java 9?


java --version
java 9.0.1
Java(TM) SE Runtime Environment (build 9.0.1+11)
Java HotSpot(TM) 64-Bit Server VM (build 9.0.1+11, mixed mode)

docker version
Client:
 Version:      17.10.0-ce
 API version:  1.33
 Go version:   go1.8.3
 Git commit:   f4ffd25
 Built:        Tue Oct 17 19:00:02 2017
 OS/Arch:      windows/amd64

Server:
 Version:      17.10.0-ce
 API version:  1.33 (minimum version 1.12)
 Go version:   go1.8.3
 Git commit:   f4ffd25
 Built:        Tue Oct 17 19:05:23 2017
 OS/Arch:      linux/amd64
 Experimental: true
  • Play Version: 2.6.7
  • Scala Version 2.12.4
  • SBT Version: 1.0.2
  • sbt-native-packager: 1.3.1

Solution

  • The error means that you are trying to run code compiled using a newer version of Java (9 which has class version 53.0) in an older version of Java (8 which has class version 52.0). So, your docker image probably has Java 8 installed. Let's do some detective work. :-)

    If I understand correctly, you are using sbt-native-packager to generate your Docker image. If so, sbt-native-packager is using openjdk:latest image as the base image, as you can see here:

    https://github.com/sbt/sbt-native-packager/blob/v1.3.1/src/main/scala/com/typesafe/sbt/packager/docker/DockerPlugin.scala#L69

    Version 1.3.1 is the version used by Play 2.6.7, as you can also see here:

    https://github.com/playframework/playframework/blob/2.6.7/framework/project/plugins.sbt#L8

    The problem is that openjdk:latest image uses Java 8. You can confirm that by looking at the latest code linked at the image page. Here is the code:

    https://github.com/docker-library/openjdk/blob/a893fe3cd82757e7bccc0948c88bfee09bd916c3/8-jdk/Dockerfile#L38-L43

    Given that, you may want to change dockerBaseImage to use a base image that uses Java 9, for example:

    dockerBaseImage := "9-jdk"
    

    You can see a complete list of image versions here: https://hub.docker.com/_/openjdk/