Create a new open-source Java project using the Gradle build tool
Tags: java, gradle, build, opensource
Published: 2021-09-08 13:06:21

---
title: Create a new open-source Java project using the Gradle build tool
published: true
date: 2021-09-02 00:00:00 UTC
tags: Java,Gradle,Build,OpenSource
canonical_url: https://MihaiBojin.com/application-settings/starting-an-open-source-java-project-with-gradle
---

![Photo: Building](https://MihaiBojin.com/static/db0fa6a41af61721f6326d3a5d922574/4968a/002-danist-soh-8Gg2Ne_uTcM-unsplash.jpg)<figcaption>"Photo by <a href="https://unsplash.com/@danist07?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Danist Soh</a> on <a href="https://unsplash.com/s/photos/build?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a>"</figcaption>

🔔 This article was originally posted on my site, [MihaiBojin.com](https://MihaiBojin.com/application-settings/starting-an-open-source-java-project-with-gradle?utm_source=DevTo&utm_medium=organic&utm_campaign=top-promo "MihaiBojin.com"). 🔔

* * *

> When building a house, you should start with a strong foundation. Similarly, creating a new open-source project requires a certain level of organization!

Roughly, here is a base minimum that makes for a decent project:

- A version control system: having it is a must-have, especially if you're planning to publish an open-source project!
- A README: help your visitors understand what the project is about and how they can find out more
- A LICENSE: choosing one early informs potential users if they can avail of the project
- A CONTRIBUTING guide: this is not precisely day one stuff, but starting one and updating it as your project develops, encourages outside contributions
- A build tool: regardless of the chosen programming language, you will need a way to manage dependencies and build or redistribute your project as binaries

Any decent build tool should be able to support:

- subprojects or modules
- code formatting
- static code analysis
- global versioning scheme
- generating sources and documentation
- running tests
- enforcing a coding standard

Let's look at all of these in detail below.

* * *

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#version-control-system)Version Control System

Most projects today use `git` hosted on GitHub. Other options exist, but they are beyond the scope of this article.

To create a new repository, take the following actions:

- Create a new organization: [https://github.com/account/organizations/new?coupon=&plan=team\_free](https://github.com/account/organizations/new?coupon=&plan=team_free)
- Create a new repository
- Choose a license (I chose MIT because it's permissive; doing so will create a `LICENSE` file in your repository)
- Here's the result: [https://github.com/props-sh/props](https://github.com/props-sh/props)

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#basic-repository-information)Basic repository information

At the very least, provide essential information, in a `README`, that helps your users understand what the project is about, how it can help them if they can use it, and how they can contribute to it.

A `LICENSE` file informs potential users about the conditions under which they can use your project. This article doesn't aim to inform about all differences between various types of licenses, but you can [read more about it here](https://choosealicense.com/).

Finally, a `CONTRIBUTING` guide will help potential developers open PRs and collaborate in your project.

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#build-tool)Build tool

And now, let's get to the 'meaty' part.

Since I'm writing a Java project, this is very opinionated. For the [first iteration](https://github.com/MihaiBojin/props) of this project, I used [Bazel](https://bazel.build/) but, since I'm starting from scratch, I thought I'd have some fun and use [Gradle](https://gradle.org/).

I started by installing [SDKman!](https://sdkman.io/usage) and then Gradle: `sdk install gradle`.

Since I'd never used it before, I started by reading the [getting started guide](https://gradle.org/guides/#getting-started). Another helpful page is [how to configure java projects](https://docs.gradle.org/7.2/userguide/building_java_projects.html).

I use [IntelliJ](https://www.jetbrains.com/idea/) as an IDE, and it has full support for Gradle using Kotlin DSL.

Next, let's configure a sound basis for a Java library made up of multiple submodules.

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#root-directory-configuration)Root directory configuration

I've set up this project as a [multi-project build](https://docs.gradle.org/current/userguide/multi_project_builds.html#sec:creating_multi_project_builds).

I started by creating a `settings.gradle.kts` file, which defines a name, and the `pluginManagement/repositories` section, which represents a set of artifact repositories to use in all (sub) projects.

```
rootProject.name = "props"

pluginManagement {
    repositories {
        mavenCentral()
        gradlePluginPortal()
    }
}
```

### [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#define-a-global-version-for-all-dependencies)Define a global version for all dependencies

I created a `build.gradle.kts` file and defined a `group` and `version`.

```
group = "sh.props"
version = project.version
```

The version is implicitly loaded from the project and can be specified in a `gradle.properties` file:

```
version=0.2.0-SNAPSHOT
```

or by passing it via the command-line, e.g., `gradle -Pversion=0.3.0 ...`

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#create-a-subproject)Create a subproject

IntelliJ can easily create subprojects:

- right-click the project and select New Module
- or press Cmd-N
- select Gradle Java module
- fill in the details and you're good to go!

Alternatively, create a new directory and inside of it:

- create a `build.gradle.kts` file
- create a Maven-like directory structure: `src/main/java`, `src/main/resources`, `src/test/java`, `src/test/resources`

Include this subproject in the `settings.gradle.kts` file:

```
include("java-props-core")
```

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#set-a-java-toolchain-version)Set a java toolchain version

Edit the subproject's `build.gradle.kts` file and define the following block to set the Java version to 11.

```
plugins {
    `java-library`
}

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(JavaVersion.VERSION_11.toString()))
    }
}

// additionally also allow incremental builds, speeding up build speed
tasks.compileJava {
    options.isIncremental = true
}
```

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#generate-source-jars-and-javadocs)Generate source JARs and Javadocs

Since `props` is a library, I wanted to generate source and documentation (Javadoc) JARs.

Luckily, this is super easy to do in Gradle. Again, edit the `build.gradle.kts` file:

```
java {
    withJavadocJar()
    withSourcesJar()
}

tasks.create<Zip>("docZip") {
    archiveFileName.set("doc.zip")
    from("doc")
}
```

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#running-tests)Running tests

I chose the JUnit 5 (Jupiter) framework, for which we need to set up a few things:

First, define a new task that will run the tests when called

```
tasks.test {
    // Use JUnit Platform for unit tests.
    useJUnitPlatform()

    // limit heap usage to 1G (can we tweaked later)
    // https://docs.gradle.org/7.2/userguide/java_testing.html#sec:test_execution
    maxHeapSize = "1G"
}
```

As well as the necessary dependencies:

```
dependencies {
    testImplementation(libs.junit.jupiter.api)
    testRuntimeOnly(libs.junit.jupiter.engine)
}
```

The `libs.junit.jupiter.api` notation represents _type-safe project dependencies_ in Gradle. These are defined in the root project settings; see below.

### [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#define-a-version-catalog)Define a version catalog

Version catalogs are an incubating feature and must be explicitly enabled.

Edit the `settings.gradle.kts` file and add the following section:

```
// enable the incubating feature
enableFeaturePreview("VERSION_CATALOGS")

dependencyResolutionManagement {
    versionCatalogs {
        create("libs") {
            // define the version once
            version("junit", "5.7.2")

            // then create aliases to each component, referencing the version above
            alias("junit-jupiter-api").to("org.junit.jupiter", "junit-jupiter-api").versionRef("junit")
            alias("junit-jupiter-engine").to("org.junit.jupiter", "junit-jupiter-engine").versionRef("junit")
        }
    }
}
```

Once the above is done, any tests deployed in `**/src/test/java` can be run by executing `gradle test`.

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#code-formatting)Code formatting

As a codebase grows, it's essential for the code to 'look' the same, as it helps give developers a consistent experience.

The chosen format (style) is less important than doing this from early on. After all, you can always change the style and reformat the codebase in one go later on!

This is, in my opinion, best done by a tool that indiscriminately auto-formats your code (as you write it)!

Gradle has a great plugin for this: [spotless](https://github.com/diffplug/spotless).

Define the plugin's version in your `settings.gradle.kts` file:

```
pluginManagement {
    plugins {
        id("com.diffplug.spotless").version("5.14.3")
    }
}
```

And add the following configuration to your `build.gradle.kts` file:

```
spotless {
    // generic formatting for miscellaneous files
    format("misc") {
        target("*.gradle", "*.md", ".gitignore")

        trimTrailingWhitespace()
        indentWithSpaces()
        endWithNewline()
    }

    // chose the Google java formatter, version 1.9
    java {
        googleJavaFormat("1.9").aosp()

        // and apply a license header
        licenseHeaderFile(rootProject.file("props.license.kt"))
    }
}
```

As you can see in the comments, it formats Java files as well as other extensions.

For Java, it uses the [google java formatter](https://github.com/google/google-java-format) and also applies a license header to every file. The `props.license.kt` contains a copy of the `LICENSE` file with a few tweaks:

- the text is a comment block: (`/* ... */`)
- and the year is programmatically filled in: (`$YEAR`)

```
/*
MIT License

Copyright (c) $YEAR Mihai Bojin

Permission is hereby granted...
*/
```

Check formatting with `gradle spotlessJavaCheck` or apply it with `gradle spotlessJavaApply`.

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#coding-standard)Coding standard

**Checking that a project's coding standard meets minimal quality criteria results in better code!**

For this I use `checkstyle`, which is also very easy to set up with Gradle:

Add the following to **settings.gradle.kts** :

```
dependencyResolutionManagement {
    versionCatalogs {
        create("libs") {
            // make a global version available
            version("checkstyle", "9.0")
        }
    }
}
```

Then edit the subproject's `build.gradle.kts` file:

```
plugins {
    checkstyle
}

checkstyle {
    // will use the version declared in the catalog
    toolVersion = libs.versions.checkstyle.get()
}
```

Run the check with `gradle checkstyleMain`.

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#smarter-static-code-analysis)Smarter static code analysis

Finally, the last component I'll be talking about in this article is `errorprone`, a library built by Google that performs smarter static code analysis. Apart from being a great standalone mistake finder, it also integrates with other projects such as [NullAway](https://github.com/uber/NullAway), a tool that helps developers find and fix `NullPointerException`s in their Java code.

Start by adding the plugin to your `settings.gradle.kts` file:

```
pluginManagement {
    plugins {
        id("net.ltgt.errorprone").version("2.0.2")
    }
}
```

And then add the following configuration to your subproject's `build.gradle.kts` file:

```
import net.ltgt.gradle.errorprone.errorprone
plugins {
    id("net.ltgt.errorprone")
}

dependencies {
    errorprone(libs.errorprone.core)
    errorprone(libs.nullaway)
}

// hook up the checker to the compilation target
tasks.withType<JavaCompile>().configureEach {
    options.errorprone.disableWarningsInGeneratedCode.set(true)
}
```

## [<svg aria-hidden="true" focusable="false" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#conclusion)Conclusion

Hopefully, this tutorial gave you an idea of the first steps you should take towards starting an open-source Java library on GitHub.

So far, I only spent a few hours learning how to do all of these from scratch and had a lot of fun doing it!

Since I haven't ported over any code from the v1 repo, I have probably yet to smooth out all the rough edges. If you end up using it, ping me [on Twitter](https://twitter.com/mihaibojin) and tell me how you got on! ( **I'd appreciate it!** )

You can find all the code referenced above [on GitHub in the props project](https://github.com/props-sh/props/commit/8243ea7c9c27c47be49dec70a3479dcd131ae2b0)!

Stay tuned for more articles in this series, and don't forget to [subscribe to my newsletter](https://motivated-founder-807.ck.page/4c5fb25380)! I'll be sending regular updates as I write more code.

Thank you and until next time!

* * *

If you liked this article and want to read more like it, [please subscribe to my newsletter](https://motivated-founder-807.ck.page/db1cf284bf "newsletter link"); I send one out every few weeks!