- Recognise the standard folder layout of a Maven/Gradle project
- Add a dependency by its coordinates (
groupId:artifactId:version) with the right scope - Run Maven lifecycle phases and Gradle tasks
Until now every program was a single Main.java file started with java Main.java. A real project, however, has hundreds of classes, dozens of external libraries (JSON, a database driver, a test framework) and several people working on it. Downloading every JAR file by hand and passing a long -cp list to javac quickly becomes a nightmare. Build tools do this job: Maven and Gradle download libraries for you, compile the code, run the tests and package a ready JAR file.
The standard project layout
Maven follows the principle of convention over configuration: files always live in the same places, so you do not have to tell the tool where to look for them. Gradle uses the same layout. The main code is in src/main/java, the tests in src/test/java, and configuration files and images in src/main/resources. A package name becomes folders: the com.educora package is the com/educora folder. The build result goes to target/ in Maven and to build/ in Gradle.
grade-book/
├── pom.xml ← Maven (Gradle: build.gradle.kts)
├── src/
│ ├── main/
│ │ ├── java/com/educora/App.java
│ │ └── resources/config.properties
│ └── test/
│ └── java/com/educora/AppTest.java
└── target/ ← build output (Gradle: build/)An external library your project needs in order to work. It is identified by three coordinates: groupId (the organisation, e.g. com.google.code.gson), artifactId (the library name, gson) and version (2.11.0). Short form: com.google.code.gson:gson:2.11.0. The tool downloads the library from the Maven Central repository and keeps it in a cache on your computer.
Maven and pom.xml
The heart of a Maven project is the **pom.xml file (Project Object Model). It holds the project's own coordinates, the Java version and the list of dependencies. The file below has two dependencies: Gson for working with JSON and JUnit for tests. The libraries that they need themselves — the transitive dependencies** — are downloaded by Maven automatically.
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.educora</groupId>
<artifactId>grade-book</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.release>21</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>pom.xml: maven.compiler.release compiles the code for Java 21Note the <scope>test</scope> line: JUnit is needed only in tests and must not end up in the finished program. The scope decides where a dependency can be used:
| Scope | Where it is visible | Example |
|---|---|---|
compile | everywhere: main code, tests and the running program (the default) | Gson |
test | only in src/test/java | JUnit, Mockito |
provided | at compile time; the server supplies it at run time | Servlet API |
runtime | only at run time, not for compiling | JDBC driver |
The Maven lifecycle
In Maven, commands are lifecycle phases that run in a strict order. When you call a phase, Maven also runs every phase before it: mvn package first validates the project, compiles it and runs the tests, and only then creates the JAR. If a test fails, the build stops — broken code is not packaged. clean is a separate phase: it deletes the old target/ folder.
| Phase | What it does |
|---|---|
validate | checks that the project is correct |
compile | compiles src/main/java into target/classes |
test | runs the tests in src/test/java |
package | creates the JAR (or WAR) file |
verify | runs extra checks such as integration tests |
install | puts the JAR into the local repository (~/.m2) |
deploy | uploads the JAR to the team's remote repository |
mvn clean package[INFO] Scanning for projects... [INFO] Building grade-book 1.0.0 [INFO] --- compiler:3.13.0:compile (default-compile) @ grade-book --- [INFO] --- surefire:3.2.5:test (default-test) @ grade-book --- [INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0 [INFO] --- jar:3.4.1:jar (default-jar) @ grade-book --- [INFO] Building jar: C:\projects\grade-book\target\grade-book-1.0.0.jar [INFO] BUILD SUCCESS
Gradle and build.gradle.kts
Gradle does the same job with a script that looks like program code instead of XML. In modern projects the script is written in Kotlin — build.gradle.kts (in older projects you will also see build.gradle, written in Groovy). Gradle has tasks instead of phases: compileJava, test, jar, build. Gradle does not rebuild parts that have not changed and caches results, so in large projects it is usually faster than Maven. Android apps are built with Gradle too.
plugins {
application
}
repositories {
mavenCentral()
}
dependencies {
implementation("com.google.code.gson:gson:2.11.0")
testImplementation("org.junit.jupiter:junit-jupiter:5.11.0")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
application {
mainClass = "com.educora.App"
}
tasks.test { useJUnitPlatform() }build.gradle.kts: implementation matches Maven's compile scope and testImplementation the test scopeThe application plugin adds the ./gradlew run task: it starts the class named in mainClass together with all its libraries. The toolchain block tells Gradle to build the project with exactly Java 21. Compare building by hand with Gradle:
# download every JAR by hand into lib/, then:
javac -d out -cp lib/gson-2.11.0.jar src/com/educora/*.java
java -cp "out:lib/gson-2.11.0.jar" com.educora.App
# a new library? download it, fix both commands again...# dependencies are listed once in build.gradle.kts
./gradlew build # download, compile, test, package
./gradlew run # start the app with all its libraries| Task | Maven | Gradle |
|---|---|---|
| Compile | mvn compile | ./gradlew compileJava |
| Run the tests | mvn test | ./gradlew test |
| Build the JAR | mvn package | ./gradlew build |
| Delete the output | mvn clean | ./gradlew clean |
| Dependency tree | mvn dependency:tree | ./gradlew dependencies |
Create a project step by step
- 1Check the JDK
Type
java -versionin a terminal: the version should be 21 or newer. - 2Create the project
In IntelliJ IDEA choose
File › New › Project: language Java, Build system Maven or Gradle, JDK 21. Entercom.educoraasGroupIdandgrade-bookasArtifactId. In a terminal, thegradle initcommand does the same job. - 3Add a dependency
Find the library's coordinates on the Maven Central website and add them to
pom.xmlorbuild.gradle.kts. Then press Reload in the IDE's Maven/Gradle panel so that the library is downloaded. - 4Build and run
mvn packageor./gradlew buildruns the tests and creates the JAR; in Gradle,./gradlew runstarts the program right away. The finished JAR is intarget/orbuild/libs/.
Key points
- Maven and Gradle download libraries, compile code, run tests and build a JAR.
- Standard layout:
src/main/java,src/main/resources,src/test/java; the output is intarget/orbuild/. - A dependency is written as
groupId:artifactId:version; its scope decides where it is visible. - Calling a Maven phase runs all earlier phases too:
package=validate→compile→test→package. - In Gradle you write
implementation/testImplementation; the wrapper (./gradlew,./mvnw) gives everyone the same version.
Check yourself
10 questions. Every correct answer earns XP.