This guide walks you through the process of using Gradle’s Build Init plugin to produce a new Java library which can be used in other JVM libraries and applications.

What you’ll build

You’ll generate a Java library that follows Gradle’s conventions.

What you’ll need

Create a library project

Gradle comes with a built-in plugin called the Build Init plugin. It is documented in the Gradle User Manual. The plugin provides a task, called init, that generates the project. The init task uses the (also built-in) wrapper task to create a Gradle wrapper script, gradlew.

The first step is to create a folder for the new project and change directory into it.

$ mkdir demo
$ cd demo

Run the init task

From inside the new project directory, run the init task and select library project type when prompted. For the other questions, press enter to use the default values.

The output will look like this, with minimal differences around versions:

$ gradle init
> Task :wrapper

Select type of project to generate:
  1: basic
  2: application
  3: library
  4: Gradle plugin
Enter selection (default: basic) [1..4] 3

Select implementation language:
  1: C++
  2: Groovy
  3: Java
  4: Kotlin
  5: Scala
  6: Swift
Enter selection (default: Java) [1..6] 3

Select build script DSL:
  1: Groovy
  2: Kotlin
Enter selection (default: Groovy) [1..2] 1

Select test framework:
  1: JUnit 4
  2: TestNG
  3: Spock
  4: JUnit Jupiter
Enter selection (default: JUnit 4) [1..4]

Project name (default: demo):

Source package (default: demo):


> Task :init
Get more help with your project: https://docs.gradle.org/5.0/userguide/java_library_plugin.html

BUILD SUCCESSFUL
2 actionable tasks: 2 executed

If you prefer the Kotlin DSL, you can select kotlin for the build script DSL. You can switch between the two DSLs for each build script details below.

The init task generates the new project with the following structure:

Groovy DSL
.
├── build.gradle
├── gradle
│   └── wrapper (1)
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
    ├── main
    │   └── java (2)
    │       └── demo
    │           └── Library.java
    └── test
        └── java (3)
            └── demo
                └── LibraryTest.java
Kotlin DSL
.
├── build.gradle.kts
├── gradle
│   └── wrapper (1)
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle.kts
└── src
    ├── main
    │   └── java (2)
    │       └── demo
    │           └── Library.java
    └── test
        └── java (3)
            └── demo
                └── LibraryTest.java
1 Generated folder for wrapper files
2 Default Java source folder
3 Default Java test folder

You now have the necessary components for a simple Java library project.

Review the generated project files

The settings file is heavily commented, but has only one active line:

Generated settings.gradle
rootProject.name = "demo" (1)
Generated settings.gradle.kts
rootProject.name = "demo" (1)
1 This assigns the name of the root project, which overrides the default behavior of naming the project after the directory it’s in.

The generated build.gradle file also has many comments. The active portion is reproduced here:

Generated build.gradle
plugins {
    id 'java-library' (1)
}

repositories {
    jcenter() (2)
}

dependencies {
    api 'org.apache.commons:commons-math3:3.6.1' (3)

    implementation 'com.google.guava:guava:28.0-jre' (4)

    testImplementation 'junit:junit:4.12' (5)
}
Generated build.gradle.kts
plugins {
    `java-library` (1)
}

repositories {
    jcenter() (2)
}

dependencies {
    api("org.apache.commons:commons-math3:3.6.1") (3)

    implementation("com.google.guava:guava:28.0-jre") (4)

    testImplementation("junit:junit:4.12") (5)
}
1 Use the java-library plugin
2 Public Bintray Artifactory repository, used to resolve project dependencies
3 This is an example of a dependency which is exported to consumers, that is to say found on their compile classpath.
4 This is an example of a dependency which is used internally, and not exposed to consumers on their own compile classpath.
5 JUnit testing library

Version numbers for the dependency declarations may vary for different Gradle versions.

The build script adds the java-library plugin. It configures the project for compiling and testing Java source code, specialized for code that is to be consumed by other projects.

The file src/main/java/demo/Library.java is shown here:

Generated src/main/java/demo/Library.java
package demo;

public class Library {
    public boolean someLibraryMethod() {
        return true;
    }
}

The generated JUnit specification, src/test/java/demo/LibraryTest.java is shown next:

Generated src/test/java/demo/LibraryTest.java
package demo;

import org.junit.Test;
import static org.junit.Assert.*;

public class LibraryTest {
    @Test public void testSomeLibraryMethod() {
        Library classUnderTest = new Library();
        assertTrue("someLibraryMethod should return 'true'", classUnderTest.someLibraryMethod());
    }
}

The generated test class has a single JUnit 4 test. The test instantiates the Library class, invokes the someLibraryMethod method, and checks that the returned value is true.

Assemble the library JAR

To build the project, run the build task. You can use the regular gradle command, but when a project includes a wrapper script, it is considered good form to use it instead.

$ ./gradlew build
> Task :compileJava
> Task :processResources NO-SOURCE
> Task :classes
> Task :jar
> Task :assemble
> Task :compileTestJava
> Task :processTestResources NO-SOURCE
> Task :testClasses
> Task :test
> Task :check
> Task :build

BUILD SUCCESSFUL
4 actionable tasks: 4 executed
The first time you run the wrapper script, gradlew, there may be a delay while that version of gradle is downloaded and stored locally in your ~/.gradle/wrapper/dists folder.

The first time you run the build, Gradle will check whether or not you already have the JUnit libraries and other listed dependencies in your cache under your ~/.gradle directory. If not, the libraries will be downloaded and stored there. The next time you run the build, the cached versions will be used. The build task compiles the classes, runs the tests, and generates a test report.

You can view the test report by opening the HTML output file, located at build/reports/tests/test/index.html.

A sample report is shown here:

Test Summary

You can find your newly packaged JAR file in the build/libs directory with the name demo.jar. Verify that the archive is valid by running the following command:

$ jar tf build/libs/demo.jar
META-INF/
META-INF/MANIFEST.MF
demo/
demo/Library.class

You should see the required manifest file —MANIFEST.MF— and the compiled Library class.

All of this happens without any additional configuration in the build script because Gradle’s java-library plugin assumes your project sources are arranged in a conventional project layout. You can customize the project layout if you wish as described in the user manual.

Congratulations, you have just completed the first step of creating a Java library! You can now customize this to your own project needs.

Customize the library JAR

You will often want the name of the JAR file to include the library version. This is easily achieved by setting a top-level version property in the build script, like so:

build.gradle
version = '0.1.0'
build.gradle.kts
version = "0.1.0"

Now run the jar task:

$ ./gradlew jar
> Task :compileJava UP-TO-DATE
> Task :processResources NO-SOURCE
> Task :classes UP-TO-DATE
> Task :jar UP-TO-DATE

BUILD SUCCESSFUL
2 actionable tasks: 2 up-to-date

and notice that the resulting JAR file at build/libs/demo-0.1.0.jar contains the version as expected.

Another common requirement is customizing the manifest file, typically by adding one or more attributes. Let’s include the library name and version in the manifest file by configuring the jar task. Add the following to the end of your build script:

build.gradle
jar {
    manifest {
        attributes('Implementation-Title': project.name,
                   'Implementation-Version': project.version)
    }
}
build.gradle.kts
tasks {
    jar {
        manifest {
            attributes(
                mapOf("Implementation-Title" to project.name,
                      "Implementation-Version" to project.version)
            )
        }
    }
}

To confirm that these changes work as expected, run the jar task again, and this time also unpack the manifest file from the JAR:

$ ./gradlew jar
$ jar xf build/libs/demo-0.1.0.jar META-INF/MANIFEST.MF

Now view the contents of the META-INF/MANIFEST.MF file and you should see the following:

META-INF/MANIFEST.MF
Manifest-Version: 1.0
Implementation-Title: demo
Implementation-Version: 0.1.0
Learn more about configuring JARs

The manifest is just one of many properties that can be configured on the jar task. For a complete list, see the Jar section of the Gradle Language Reference as well as the Jar and Creating Archives sections of the Gradle User Manual.

Adding API documentation

The java-library plugin has built-in support for Java’s API documentation tool via the javadoc task.

The code generated by the Build Init plugin already placed a comment on the Library.java file. Modify the comment to become javadoc markup.

src/main/java/Library.java
/**
 * This java source file was generated by the Gradle 'init' task.
 */
package demo;

public class Library {
    public boolean someLibraryMethod() {
        return true;
    }
}

Run the javadoc task.

$ ./gradlew javadoc
> Task :compileJava UP-TO-DATE
> Task :processResources NO-SOURCE
> Task :classes UP-TO-DATE
> Task :javadoc

BUILD SUCCESSFUL
2 actionable tasks: 1 executed, 1 up-to-date

You can view the generated javadoc files by opening the HTML file located at build/docs/javadoc/index.html.

Generating Javadoc and Sources JAR

You can easily generate a Javadoc JAR for your library:

build.gradle
java {
    withJavadocJar()
}
build.gradle.kts
java {
    withJavadocJar()
}

Similarly, you can use withSourcesJar() to also generate a JAR containing the project source files.

Additional JARs defined that way will be produced by the assemble task and will be part of the publication. The resulting files will be found in build/libs, with a name using the conventional classifier -javadoc or -sources.

Summary

That’s it! You’ve now successfully built a Java library project, packaged it as a JAR and configured extra JARs. Along the way, you’ve learned how to:

  • Generate a Java library, learn how it is structured

  • Adapt the generated build.gradle and sample Java files

  • Run the build and view the test report

  • Customize the name of the JAR file and the content of its manifest

  • Generate API documentation, including making a JAR for it

Now you could complete this exercise by trying to compile some Java code that uses the library you just built.

Next steps

Building a library is just one aspect of reusing code across project boundaries. From here, you may be interested in:

Help improve this guide

Have feedback or a question? Found a typo? Like all Gradle guides, help is just a GitHub issue away. Please add an issue or pull request to gradle/guides and we’ll get back to you.