GradleによるJavaライブラリの作成と利用
構成
以下のような sample.core に依存した sample.lib を使用した sample-gradle アプリを作成する。
─ sample-gradle
└ sample.lib
└ sample.core
Building Java Libraries Sample
sample-gradle-core
sample.core を作成する。
mkdir sample-gradle-core cd sample-gradle-core gradle init
パッケージは以下のように変更する。
> Source package (default: sample.gradle.core): com.oximeeg.sample.core
build.gradle
plugins {
id 'java-library'
id 'maven-publish'
}
repositories {
mavenLocal()
}
publishing {
publications {
mavenJava(MavenPublication) {
group = 'com.oximeeg'
artifactId = 'sample.core'
version = '1.0.0'
from components.java
}
}
}
Core.java
package com.oximeeg.sample.core; public class Core { public String echo(String arg1) { return "CoreMethod arg1:" + arg1; } }
ローカルホストに公開
gradle clean publishToMavenLocal
sample-gradle-lib
sample.lib を作成する。
mkdir sample-gradle-lib cd sample-gradle-lib gradle init
パッケージは以下のように変更する。
> Source package (default: sample.gradle.lib): com.oximeeg.sample.lib
build.gradle
plugins {
id 'java-library'
id 'maven-publish'
}
repositories {
mavenLocal()
}
dependencies {
implementation 'com.oximeeg:sample.core:1.0.0'
}
publishing {
publications {
mavenJava(MavenPublication) {
group = 'com.oximeeg'
artifactId = 'sample.lib'
version = '1.0.0'
from components.java
}
}
}
Library.java
package com.oximeeg.sample.lib; import com.oximeeg.sample.core.Core; public class Library { public String echo() { return new Core().echo("Hello World"); } }
ローカルホストに公開
gradle clean publishToMavenLocal
Building Java Applications Sample
sample-gradle
アプリを作成する。
mkdir sample-gradle cd sample-gradle gradle init
パッケージは以下のように変更する。
> Source package (default: sample.gradle): com.oximeeg.sample.app
build.gradle
plugins {
id 'application'
}
repositories {
mavenLocal()
}
dependencies {
implementation 'com.oximeeg:sample.lib:1.0.0'
}
application {
mainClass = 'com.oximeeg.sample.app.App'
}
App.java
package com.oximeeg.sample.app; import com.oximeeg.sample.lib.Library; public class App { public String getGreeting() { return new Library().echo(); } public static void main(String[] args) { System.out.println(new App().getGreeting()); } }
実行
- ビルド -
gradle build - 実行 -
gradle run
依存関係
- 確認 -
gradle app:dependencies --configuration runtimeClasspath
runtimeClasspath - Runtime classpath of source set 'main'.
\--- com.oximeeg:sample.lib:1.0.0
\--- com.oximeeg:sample.core:1.0.0
推移的な依存関係
ライブラリを利用する際の注意点に 推移的な依存関係 がある。依存しているライブラリのバージョンが競合した際の解決方法も知識として知っておいた方が良い。
例
sample.coreを以下のように更新する。
- build.gradle
- version = '1.0.0'
+ version = '2.0.0'
- Core.java
- public String echo(String arg1) {
- return "CoreMethod arg1:" + arg1;
+ public String echo(String arg1, String arg2) {
+ return "CoreMethod arg1:" + arg1 + " arg2:" + arg2;
アプリの依存関係に core:2.0.0 を追加する。
- build.gradle
dependencies {
implementation 'com.oximeeg:sample.lib:1.0.0'
implementation 'com.oximeeg:sample.core:2.0.0'
}
実行
- ビルド -
gradle build - 実行 -
gradle run
Exception in thread "main" java.lang.NoSuchMethodError: 'java.lang.String com.oximeeg.sample.core.Core.echo(java.lang.String)'
at com.oximeeg.sample.lib.Library.echo(Library.java:7)
at com.oximeeg.sample.app.App.getGreeting(App.java:7)
at com.oximeeg.sample.app.App.main(App.java:11)
依存関係
- 確認 -
gradle app:dependencies --configuration runtimeClasspath
runtimeClasspath - Runtime classpath of source set 'main'.
+--- com.oximeeg:sample.lib:1.0.0
| \--- com.oximeeg:sample.core:1.0.0 -> 2.0.0
\--- com.oximeeg:sample.core:2.0.0
何が起きたのか
ビルドは成功したのに、実行時に Exception が発生した。
依存関係を見ると sample.lib の依存していた sample.core のバージョンが v2.0.0 に変更されている。
sample.lib は sample.core の v1.0.0 を使用するつもりなのに v2.0.0 に更新されたことで echo(String arg1) が echo(String arg1, String arg2) に変更されているが、echo(String arg1) を呼び出そうとした結果、NoSuchMethodError が発生した。
- Java は同じパッケージのライブラリを複数バージョン同時に利用することはできない。
- ビルド通れば問題ないと考えるの間違い
結局
不要な依存関係を exclude で除外したり、整合性の取れた依存関係になるようにライブラリのバージョンを調整する。