How to do multi-project in Gradle.
Before multi-project, first try creating and running a jar file in a single project.
gradle initialization
$ gradle init
Select type of project to generate:
1: basic
2: application
3: library
4: Gradle plugin
Enter selection (default: basic) [1..4] 1
Select build script DSL:
1: Groovy
2: Kotlin
Enter selection (default: Groovy) [1..2] 1
Project name (default: JavaMultiProject):
> Task :init
Get more help with your project: https://guides.gradle.org/creating-new-gradle-builds
BUILD SUCCESSFUL in 6s
2 actionable tasks: 2 executed
Modify the automatically created build.gradle file a bit. The important thing is to create the jar task.
build.gradle
apply plugin: 'java'
apply plugin: 'application'
sourceCompatibility = 11
targetCompatibility = 11
repositories {
jcenter()
}
dependencies {
}
mainClassName = 'App'
jar {
manifest {
attributes 'Main-Class': "App"
}
}
Create a source to run.
src/main/java/App.java
public class App {
public static void main(String[] args) {
System.out.println("Hello");
}
}
build and run
$ gradle build
BUILD SUCCESSFUL in 2s
5 actionable tasks: 1 executed, 4 up-to-date
$ java -jar build/libs/JavaMultiProject.jar
Hello
You have successfully created and run the jar file in a single project.
Now let's create a multi-project.
This is the directory structure.
Constitution
.(JavaMultiProject)
├── bar (Application project)
│ ├── src
│ ├── build.gradle
├── foo (Application project)
│ ├── src
│ ├── build.gradle
├── share (Project to be used as a common library)
│ ├── src
│ ├── build.gradle
├── build.gradle
├── setting.gradle
Create a directory.
python
$ mkdir -p bar/src/main/java
$ mkdir -p foo/src/main/java
$ mkdir -p share/src/main/java
If you want to make a multi-project, set it in setting.gradle.
Specify the subproject in include.
setting.gradle
rootProject.name = 'JavaMultiProject'
include 'foo', 'bar', 'share'
This makes each for`` bar
share
directory recognized as a subproject.
IntelliJ IDEA also recognizes the project in this way.
In build.gradle that exists in the project root, specify the settings that apply to all subprojects by specifying subprojects.
build.gradle(root)
allprojects {
}
subprojects {
apply plugin: 'java'
sourceCompatibility = 11
targetCompatibility = 11
repositories {
jcenter()
}
}
Next is the subproject build.gradle.
Let's start with the application project bar
.
bar/build.gradle
apply plugin: 'application'
dependencies {
implementation project(":share")
}
mainClassName = 'com.example.Bar'
jar {
manifest {
attributes 'Main-Class': "com.example.Bar"
}
from configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
To explain the important part, The ʻimplementation project (": share") `in dependencies defines that it depends on another subproject, share.
I also specified from ~
in the jar task, which means that the dependent libraries are included in the jar of the Bar project.
By the way, if the from method does not exist, the NoClassDefFoundError
error will be output because the dependent library is not included in the jar. Just in case I got stuck with this.
python
$ java -jar bar/build/libs/bar.jar
Exception in thread "main" java.lang.NoClassDefFoundError: com/example/Hello
at com.example.Bar.main(Bar.java:5)
Caused by: java.lang.ClassNotFoundException: com.example.Hello
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:521)
... 1 more
The foo project is almost the same as the bar project, but I'll mention it just in case. Only mainClassName is changed to Foo.
foo/build.gradle
apply plugin: 'application'
dependencies {
implementation project(":share")
}
mainClassName = 'com.example.Foo'
jar {
manifest {
attributes 'Main-Class': "com.example.Foo"
}
from configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
share's build.gradle doesn't mention anything this time.
share/build.gradle
Finally, I will write the code.
bar/src/main/java/com/exmaple/Bar.java
package com.example;
public class Bar {
public static void main(String[] args) {
var hello = new Hello("Bar");
System.out.println(hello.say());
}
}
foo/src/main/java/com/exmaple/Foo.java
package com.example;
public class Foo {
public static void main(String[] args) {
var hello = new Hello("Foo");
System.out.println(hello.say());
}
}
share/src/main/java/com/exmaple/Hello.java
package com.example;
public class Hello {
private final String name;
public Hello(String name) {
this.name = name;
}
public String say() {
return name + " Hello!";
}
}
I will try to build.
Subproject tasks are executed with : (project name): (task name)
.
Also, the build of the share project on which bar depends will be executed at the same time.
python
$ gradle :bar:build
BUILD SUCCESSFUL in 804ms
7 actionable tasks: 7 up-to-date
$ ls -l bar/build/libs/
total 8
-rw-r--r-- 1 ysaito staff 1591 4 29 21:15 bar.jar
If you unzip the created jar for reference, you can see that Hello.class inside the share is included in the created bar.jar.
Unzip the jar and check
$ jar xvf bar.jar
META-INF/Was created
META-INF/MANIFEST.MF was deployed
com/Was created
com/example/Was created
com/example/Bar.class has been expanded
com/example/Hello.class has been expanded
Now that the jar is created, let's run it.
python
$ java -jar bar/build/libs/bar.jar
Bar Hello!
$ java -jar foo/build/libs/foo.jar
Foo Hello!
Gradle User Guide-> Build Multi-Project
Recommended Posts