Learn the basics of authoring Gradle by first creating a Java app using Gradle init.

In this section, you will:

  • Initialize a Java project

  • Review the directory layout

  • Run a Java application

  • Produce a Build Scan

  • Bundle the application in an archive

Step 0. Before you Begin

  1. Make sure you have Gradle installed.

  2. Install IntelliJ IDEA. The Community Edition is a free version of IntelliJ IDEA.

Step 1. Initializing the Project

Create a new directory called authoring-tutorial and cd into it:

$ mkdir authoring-tutorial
$ cd authoring-tutorial

Run gradle init with parameters to generate a Java application:

$ gradle init --use-defaults --type java-application
In this tutorial, Kotlin DSL is used to build a simple Java project (as it is the default DSL starting in Gradle 8.2). All examples are macOS based.

Step 2. Understanding the Directory layout

The project root directory contains all source files from your project.

When you are done with Gradle init, the directory should look as follows:

.
├── gradle                              (1)
│   └── wrapper
├── gradlew                             (2)
├── gradlew.bat                         (2)
├── settings.gradle.kts                 (3)
└── app
    ├── build.gradle.kts                (4)
    └── src
        ├── main
        │   └── java                    (5)
        │       └── demo
        │           └── App.java
        └── test
            └── java                    (6)
                └── demo
                    └── AppTest.java
1 Generated folder for wrapper files
2 Gradle wrapper start scripts
3 Settings file to define build name and subprojects
4 Build script for app subproject
5 Default Java source folder for app subproject
6 Default Java test source folder for app subproject

The authoring-tutorial folder is the root project directory. Inside the root project directory are one or more subprojects, build scripts, and the Gradle wrapper.

While the Gradle Wrapper is local to the root project, the Gradle executable is found in the GRADLE_USER_HOME.

The GRADLE_USER_HOME, which defaults to USER_HOME/.gradle, is also where Gradle stores its global configuration properties, initialization scripts, caches, log files and more.

Step 3. Review the Gradle Files

The settings.gradle.kts file has two interesting lines:

settings.gradle.kts
rootProject.name = "authoring-tutorial"
include("app")
  • rootProject.name assigns a name to the build, overriding the default behavior of naming the build after its directory name.

  • include("app") defines that the build consists of one subproject called app that contains its own source code and build logic.

More subprojects can be added by additional include() statements.

Our build contains one subproject called app representing the Java application we are building. It is configured in the app/build.gradle(.kts) file:

build.gradle.kts
plugins {
    id("application")                                               (1)
}

repositories {
    mavenCentral()                                                  (2)
}

dependencies {
    testImplementation("org.junit.jupiter:junit-jupiter:5.9.3")     (3)
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
    implementation("com.google.guava:guava:32.1.1-jre")             (4)
}

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(11)                (5)
    }
}

application {
    mainClass = "org.example.App"                                   (6)
}

tasks.named<Test>("test") {
    useJUnitPlatform()                                              (7)
}
1 Apply the application plugin to add support for building a CLI application in Java.
2 Use Maven Central for resolving dependencies.
3 Use JUnit Jupiter for testing.
4 This dependency is used by the application.
5 Define the toolchain version.
6 Define the main class for the application.
7 Use JUnit Platform for unit tests.

The build script in the app subproject directory declares the dependencies the app code will need to be assembled and tested.

Step 4. Review the Code

The file app/src/main/java/authoring/tutorial/App.java contains the main class of the project:

App.java
package authoring.tutorial;

public class App {
    public String getGreeting() {
        return "Hello World!";
    }

    public static void main(String[] args) {
        System.out.println(new App().getGreeting());
    }
}

The code prints out a simple "Hello World" greeting to the screen.

A test class is available at app/src/test/java/authoring/tutorial/AppTest.java:

AppTest.java
package authoring.tutorial;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class AppTest {
    @Test void appHasAGreeting() {
        App classUnderTest = new App();
        assertNotNull(classUnderTest.getGreeting(), "app should have a greeting");
    }
}

The generated test class has a single JUnit Jupiter test. The test instantiates the App class, invokes a method on it, and checks that it returns the expected value.

Step 5. Run the App

The Application plugin, which was automatically added by gradle init, facilitates creating an executable JVM application:

plugins {
    id("application")
}

Applying the Application plugin implicitly applies the Java plugin and adds tasks like assemble, build, and run to our project.

Thanks to the application plugin, you can run the application directly from the command line. The run task tells Gradle to execute the main method in the class assigned to the mainClass property.

$ ./gradlew run

> Task :app:run
Hello World!

BUILD SUCCESSFUL in 998ms
2 actionable tasks: 2 executed

Step 6. Bundle the App

The application plugin packages the application, with all its dependencies, for you. The archive will also contain a script to start the application with a single command.

Run ./gradlew build:

$ ./gradlew build

> Task :app:compileJava
> Task :app:processResources NO-SOURCE
> Task :app:classes
> Task :app:jar
> Task :app:startScripts
> Task :app:distTar
> Task :app:distZip
> Task :app:assemble
> Task :app:compileTestJava
> Task :app:processTestResources NO-SOURCE
> Task :app:testClasses
> Task :app:test
> Task :app:check
> Task :app:build

BUILD SUCCESSFUL in 5s

If you run a full build as shown above, Gradle will have produced the archive in two formats: app/build/distributions/app.tar and app/build/distributions/app.zip.

Step 6. Publish a Build Scan

The best way to learn more about what your build is doing behind the scenes is to publish a Build Scan. To do so, run the build task again with the --scan flag.

$ ./gradlew build --scan
> Task :app:compileJava UP-TO-DATE
> Task :app:processResources NO-SOURCE
> Task :app:classes UP-TO-DATE
> Task :app:jar UP-TO-DATE
> Task :app:startScripts UP-TO-DATE
> Task :app:distTar UP-TO-DATE
> Task :app:distZip UP-TO-DATE
> Task :app:assemble UP-TO-DATE
> Task :app:compileTestJava UP-TO-DATE
> Task :app:processTestResources NO-SOURCE
> Task :app:testClasses UP-TO-DATE
> Task :app:test UP-TO-DATE
> Task :app:check UP-TO-DATE
> Task :app:build UP-TO-DATE

BUILD SUCCESSFUL in 1s
7 actionable tasks: 7 up-to-date
Resolving local hostname is slow, see https://gradle.com/help/gradle-slow-host-name

Publishing a build scan to scans.gradle.com requires accepting the Gradle Terms of Service defined at https://gradle.com/terms-of-service. Do you accept these terms? [yes, no] yes

Gradle Terms of Service accepted.

Publishing build scan...
https://gradle.com/s/7ee5saas3seo2

Click the link and explore which tasks were executed, which dependencies were downloaded, and many more details:

build scan 3

Next Step: The Build Lifecycle >>