Help us understand the problem. What is going on with this article?

GradleでJavaのビルド時にJDKを動的に切り替える方法

はじめに

OpenJDK11 が 2018 年の 9 月にリリースされました。エンタープライズな案件で Java を使うとすると JDK11 が多いのではないでしょうか。
また、すでに JDK8 を使っているけど、新しく導入される一部のプロジェクトでは JDK11 を採用したい、という声もちらほら聞きます。

今回は JDK8 を使っているが JDK11 での検証を始めたときに、Gradle でのビルドを JDK8 と JDK11 の両方に対応したい(ビルドしたい)という場合に、どのようなビルド設定がよいのか考えました。なお JDK の変更にバージョンアップに伴うアプリケーションの修正、チューニングなどは、必要事項と思いますが、本記事からは除きます。あくまでビルド時に JDK を動的に切り替える方法に焦点を当てたいと思います。

設定内容

1. build.gradlesourceCompatibility, targetCompatibility でパラメータを指定

JDK のバージョンについては build.gradle に固定値で指定していることが多いと思います。(あるいは gradle.properties に記載)

以下のようなイメージです。

build.gradle
...

sourceCompatibility = 1.8
targetCompatibility = 1.8

...

あるいは gradle.properties に値を記載しているとすると

build.gradle
...

sourceCompatibility = javaVersion
targetCompatibility = javaVersion

...
gradle.properties
...
javaVersion=1.8
...

というイメージです。

ビルド実行時に動的に切り替えたいので、 build.gradle の定義は

build.gradle
...

sourceCompatibility = javaVersion
targetCompatibility = javaVersion

...

と変数で定義しておきます。

2. ビルド時にパラメータで JDK のバージョンと JAVA_HOME を設定

gradle-Pkey=value でパラメータを指定できます。これを利用して、gradle build -PjavaVersion=1.11 などとすればビルド実行時に JDK のバージョンを指定できます。合わせて Gradle が用いる JDK を指定する必要があります。これは org.gradle.java.home パラメータで指定することができます。

よって

gradle build -PjavaVersion=1.11 -Dorg.gradle.java.home="C:\java\11 --info"

のようにすれば良いのではないでしょうか。

確認

プロジェクト構成

以下のようなプロジェクト構成にしておきます。

C:
└─src
    └─main
       ├─java
       │  └─sample
       │      └─gradle
       │          └─multiversion
       │              Sample.java
       └─resources
build.gradle
plugins {
    id 'java-library'
}

repositories {
    jcenter()
}

dependencies {
}

sourceCompatibility = javaVersion
targetCompatibility = javaVersion

JDK11 でビルド & 確認

JDK11 でビルドします。

>gradle build -PjavaVersion=1.11 -Dorg.gradle.java.home="C:\java\11"

BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed

実際にコンパイルされた class ファイルについて javap -v でビルドされたバージョンを確認します。

以下の実行結果からわかるように major version: 55 と JDK11 でビルドされていることがわかります。

C:\workspace\sample-gradle-multiversion>javap -v build\classes\java\main\sample\gradle\multiversion\Sample.class
Classfile /C:/workspace/sample-gradle-multiversion/build/classes/java/main/sample/gradle/multiversion/Sample.class
  Last modified 2019/07/12; size 576 bytes
  MD5 checksum 580cd2384cb91a31c14e09339617ba75
  Compiled from "Sample.java"
public class sample.gradle.multiversion.Sample
  minor version: 0
  major version: 55
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #5                          // sample/gradle/multiversion/Sample
  super_class: #6                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 1
Constant pool:
   #1 = Methodref          #6.#20         // java/lang/Object."<init>":()V
   #2 = Fieldref           #21.#22        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #23            // Hello world.
   #4 = Methodref          #24.#25        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #5 = Class              #26            // sample/gradle/multiversion/Sample
   #6 = Class              #27            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lsample/gradle/multiversion/Sample;
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = Utf8               args
  #17 = Utf8               [Ljava/lang/String;
  #18 = Utf8               SourceFile
  #19 = Utf8               Sample.java
  #20 = NameAndType        #7:#8          // "<init>":()V
  #21 = Class              #28            // java/lang/System
  #22 = NameAndType        #29:#30        // out:Ljava/io/PrintStream;
  #23 = Utf8               Hello world.
  #24 = Class              #31            // java/io/PrintStream
  #25 = NameAndType        #32:#33        // println:(Ljava/lang/String;)V
  #26 = Utf8               sample/gradle/multiversion/Sample
  #27 = Utf8               java/lang/Object
  #28 = Utf8               java/lang/System
  #29 = Utf8               out
  #30 = Utf8               Ljava/io/PrintStream;
  #31 = Utf8               java/io/PrintStream
  #32 = Utf8               println
  #33 = Utf8               (Ljava/lang/String;)V
{
  public sample.gradle.multiversion.Sample();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 6: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lsample/gradle/multiversion/Sample;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String Hello world.
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 10: 0
        line 12: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  args   [Ljava/lang/String;
}
SourceFile: "Sample.java"

JDK 11 でビルドした class ファイルを削除するために gradle clean しておきます。

C:\workspace\sample-gradle-multiversion>gradle clean -PjavaVersion=1.11

BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed

JDK8 でビルド & 確認

次に JDK8 でビルドします。

C:\workspace\sample-gradle-multiversion>gradle build -PjavaVersion=1.8 -Dorg.gradle.java.home="C:\java\8"

BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed

class ファイルを確認します。 major version: 52 と JDK8 でビルドされていることがわかります。

C:\workspace\sample-gradle-multiversion>javap -v build\classes\java\main\sample\gradle\multiversion\Sample.class
Classfile /C:/workspace/sample-gradle-multiversion/build/classes/java/main/sample/gradle/multiversion/Sample.class
  Last modified 2019/07/12; size 576 bytes
  MD5 checksum ea23dd24700da60b773d93f8ff2f9d77
  Compiled from "Sample.java"
public class sample.gradle.multiversion.Sample
  minor version: 0
  major version: 52
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #5                          // sample/gradle/multiversion/Sample
  super_class: #6                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 1
Constant pool:
   #1 = Methodref          #6.#20         // java/lang/Object."<init>":()V
   #2 = Fieldref           #21.#22        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #23            // Hello world.
   #4 = Methodref          #24.#25        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #5 = Class              #26            // sample/gradle/multiversion/Sample
   #6 = Class              #27            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lsample/gradle/multiversion/Sample;
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = Utf8               args
  #17 = Utf8               [Ljava/lang/String;
  #18 = Utf8               SourceFile
  #19 = Utf8               Sample.java
  #20 = NameAndType        #7:#8          // "<init>":()V
  #21 = Class              #28            // java/lang/System
  #22 = NameAndType        #29:#30        // out:Ljava/io/PrintStream;
  #23 = Utf8               Hello world.
  #24 = Class              #31            // java/io/PrintStream
  #25 = NameAndType        #32:#33        // println:(Ljava/lang/String;)V
  #26 = Utf8               sample/gradle/multiversion/Sample
  #27 = Utf8               java/lang/Object
  #28 = Utf8               java/lang/System
  #29 = Utf8               out
  #30 = Utf8               Ljava/io/PrintStream;
  #31 = Utf8               java/io/PrintStream
  #32 = Utf8               println
  #33 = Utf8               (Ljava/lang/String;)V
{
  public sample.gradle.multiversion.Sample();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 6: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lsample/gradle/multiversion/Sample;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String Hello world.
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 10: 0
        line 12: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  args   [Ljava/lang/String;
}
SourceFile: "Sample.java"

結論

  1. build.gradlesourceCompatibility, targetCompatibility に変数で定義
  2. Gradleのビルド時にパラメータ -P で JDK のバージョンと -Dorg.gradle.java.homeJAVA_HOME を設定
future
ITを武器とした課題解決型のコンサルティングサービスを提供します
http://future-architect.github.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした