Create a new open-source Java project using the Gradle build tool

Photo: Building
“Photo by Danist Soh on Unsplash
  • 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
  • subprojects or modules
  • code formatting
  • static code analysis
  • global versioning scheme
  • generating sources and documentation
  • running tests
  • enforcing a coding standard

Version Control System

Basic repository information

Build tool

Root directory configuration

rootProject.name = "props"

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

Define a global version for all dependencies

group = "sh.props"
version = project.version
version=0.2.0-SNAPSHOT

Create a subproject

  • 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!
  • 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("java-props-core")

Set a java toolchain version

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
}

Generate source JARs and Javadocs

java {
withJavadocJar()
withSourcesJar()
}

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

Running tests

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"
}
dependencies {
testImplementation(libs.junit.jupiter.api)
testRuntimeOnly(libs.junit.jupiter.engine)
}

Define a version catalog

// 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")
}
}
}

Code formatting

pluginManagement {
plugins {
id("com.diffplug.spotless").version("5.14.3")
}
}
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"))
}
}
  • 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...
*/

Coding standard

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

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

Smarter static code analysis

pluginManagement {
plugins {
id("net.ltgt.errorprone").version("2.0.2")
}
}
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)
}

Conclusion

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Mihai Bojin

Mihai Bojin

Software Engineer at heart, Manager by day, Indie Hacker at night. Writing about DevOps, Software engineering, and Cloud computing. Opinions my own.