
Java Tutorial 2025 Day 01: Hello CLI
Post Date : 2025-06-28T15:19:22+07:00
Modified Date : 2025-06-28T15:19:22+07:00
Category: java
Tags: java
SourceCode
Create Main App
mkdir -p src/main/java/com/nextjsvietnam
package com.nextjsvietnam;
public class App {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
Set the appropriate java version
touch .sdkmanrc
sdk env
mvn --version
.sdkmanrc content
java=22-oracle
Build and run with maven cli
mvn
Maven Cheatsheet
Command | Description |
---|---|
mvn validate |
Validate that the project’s pom.xml is correct and all necessary information is available. |
mvn compile |
Compile source code of the project. |
mvn test-compile |
Compile test source code. |
mvn test |
Run tests using a suitable unit testing framework (e.g. JUnit). |
mvn package |
Take the compiled code and package it (e.g. JAR, WAR). |
mvn verify |
Run any checks on results of integration tests to ensure quality criteria. |
mvn install |
Install the package into the local repository, for use as a dependency in other projects. |
mvn deploy |
Copy the final package to the remote repository for sharing with other developers. |
Command | Description |
---|---|
mvn clean |
Remove the target/ directory with all build output. |
mvn site |
Generate a site (documentation, reports) for the project. |
mvn site:run |
Generate and serve the project site on a local web server. |
mvn dependency:tree |
Print the dependency hierarchy for the project. |
mvn dependency:analyze |
Analyze declared vs. used dependencies. |
mvn help:effective-pom |
Display the effective POM as seen by Maven (after inheritance and interpolation). |
mvn help:describe |
Show detailed information about a plugin or goal (e.g. mvn help:describe -Dplugin=compiler ). |
mvn help:help |
Display help for Maven itself or for a specific plugin/goal. |
Typical workflow with maven
# 1. Clean, compile, run tests, package, install to local repo
mvn clean install
# 2. Clean, compile, package, then run your main class
mvn clean package exec:java -Dexec.mainClass=com.nextjsvietnam.App
# 3. Quickly compile and test with debug output
mvn clean test -X
# 4. Dependency analysis and tree
mvn dependency:analyze dependency:tree
# 5. Generate site and open locally
mvn site site:run
Add new package to POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.nextjsvietnam</groupId>
<artifactId>ret_java_cli_001</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>22</maven.compiler.source>
<maven.compiler.target>22</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<!-- Ensure the compiler uses the release flag -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<release>22</release>
</configuration>
</plugin>
<!-- Upgrade the dependency plugin to a version that understands Java 22 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.8.1</version>
</plugin>
</plugins>
</build>
</project>
Create a Makefile
# Load environment vars from .env (must be in KEY=VALUE format)
-include .env
# Default to 'local' if ENVIRONMENT isn't set in .env
ENVIRONMENT ?= local
# Project root
ROOT_DIR := $(shell pwd)
# Maven command
MVN := mvn
# Your main class
MAIN_CLASS := com.nextjsvietnam.App
# Phony targets
.PHONY: all install run clean package
# Default target
all: install
install: ## Install dependencies and build the project
@echo "[$(ENVIRONMENT)] Installing and building in $(ROOT_DIR)"
@$(MVN) clean install
run: install ## Build and run the application
@echo "[$(ENVIRONMENT)] Running application"
@$(MVN) clean package exec:java -Dexec.mainClass=$(MAIN_CLASS)
clean: ## Clean up build artifacts
@echo "[$(ENVIRONMENT)] Cleaning project"
@$(MVN) clean
package: install ## Clean up build artifacts
@echo "[$(ENVIRONMENT)] Package project"
@$(MVN) package
make
make install
make run
make clean
make package
Output file stay at
./target/ret_java_cli_001-1.0-SNAPSHOT.jar
Run a java jar
java -cp "./target/ret_java_cli_001-1.0-SNAPSHOT.jar:lib/*" com.nextjsvietnam.App
java
Invoke the Java Virtual Machine.
-cp (or -classpath)
Sets the classpath—the list of places the JVM searches for .class files and JARs.
"my-app-1.0-SNAPSHOT.jar:lib/*"
my-app-1.0-SNAPSHOT.jar
Your application’s own JAR.
:
Classpath separator on macOS/Linux (; on Windows).
lib/*
“All JARs in the lib/ directory.” Any third-party libraries you copied there via mvn dependency:copy-dependencies.
com.mycompany.app.App
The fully-qualified name of the class whose public static void main(String[]) you want to run.
Ship to developer or enduser
Ship to developer
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.nextjsvietnam</groupId>
<artifactId>ret_java_cli_001</artifactId>
<version>1.0</version>
<properties>
<maven.compiler.source>22</maven.compiler.source>
<maven.compiler.target>22</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<!-- Ensure the compiler uses the release flag -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<release>22</release>
</configuration>
</plugin>
<!-- Upgrade the dependency plugin to a version that understands Java 22 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>com.nextjsvietnam.App</Main-Class>
<Build-Number>2025962801</Build-Number>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Ship to end users
Shade + Appassembler
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.nextjsvietnam</groupId>
<artifactId>ret_java_cli_001</artifactId>
<version>1.0</version>
<properties>
<maven.compiler.source>22</maven.compiler.source>
<maven.compiler.target>22</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<!-- Ensure the compiler uses the release flag -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<release>22</release>
</configuration>
</plugin>
<!-- Upgrade the dependency plugin to a version that understands Java 22 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>com.nextjsvietnam.App</Main-Class>
<Build-Number>2025962801</Build-Number>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>2.1.0</version>
<executions>
<execution>
<id>generate-scripts</id>
<phase>package</phase>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
<configuration>
<programs>
<program>
<mainClass>com.nextjsvietnam.App</mainClass>
<name>greeting_cli</name>
</program>
</programs>
<repositoryName>repo</repositoryName>
<assembleDirectory>${project.build.directory}/app</assembleDirectory>
</configuration>
</plugin>
</plugins>
</build>
</project>
Output
./target/app/bin/greeting_cli
./target/app/bin/greeting_cli.bat
When to choose which ?
Shade-only
- ✅ You need the simplest build.
- ✅ Your users don’t mind java -jar ….
- ✅ You’re distributing it as part of another package or Docker image.
Shade + Appassembler
- ✅ You want a frictionless, “native” CLI feel.
- ✅ You need both Unix and Windows launchers.
- ✅ You’re handing this tool to non-Java users.
Either way, you end up with a self-contained artifact. If minimal setup is your goal, go with Shade-only; if maximum polish and ease of use is your goal, add Appassembler.