Development Guide
Best practices, workflows, and advanced usage for productive Java 25 development
Development Workflow
Recommended workflow for daily development with the template's tools and configurations.
Start Development
./mvnw compile # Compile and format check
./mvnw test # Run unit tests
Write Code & Tests
Write your implementation in src/main/java and corresponding tests in src/test/java
Continuous Testing
./mvnw test -Dtest=YourTestClass # Run specific test
./mvnw spotless:apply # Format code
Pre-commit Validation
./mvnw verify # Full build with all tests
Testing Strategy
Comprehensive testing approach with unit tests, integration tests, property-based testing, and architecture validation.
Unit Tests
Fast, isolated tests using JUnit 5 and AssertJ. Filename pattern: *Test.java
./mvnw test # Runs only unit tests
Integration Tests
Component and system integration tests. Filename pattern: *IT.java
./mvnw integration-test # Runs only IT tests
Property-Based Testing
Automated test case generation with jqwik for discovering edge cases.
@Property
void testProperty(@ForAll int value) {
// Test logic with generated values
}
Architecture Tests
Validate architectural rules and code structure with ArchUnit.
@Test
void layersShouldBeRespected() {
layeredArchitecture()
.whereLayer("Controller").mayNotAccessAnyLayer()
.check(classes);
}
Test Configuration Example
Unit Test Example
@ExtendWith(MockitoExtension.class)
class ServiceTest implements WithAssertions {
@Mock
private Repository repository;
@InjectMocks
private Service service;
@Test
void shouldReturnExpectedResult() {
// given
var input = create(InputData.class);
when(repository.find(any())).thenReturn(expectedData);
// when
var result = service.process(input);
// then
assertThat(result).satisfies(data -> {
assertThat(data.getId()).isNotNull();
assertThat(data.getValue()).isEqualTo(expected);
});
}
}
Integration Test Example
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class ApplicationIT implements WithAssertions {
private TestContainer container;
@BeforeAll
void startContainer() {
container = new TestContainer().start();
}
@Test
void shouldProcessCompleteWorkflow() {
// Full integration test
var result = application.processWorkflow(testData);
assertThat(result)
.hasFieldOrPropertyWithValue("status", "SUCCESS")
.hasFieldOrPropertyWithValue("processed", true);
}
@AfterAll
void stopContainer() {
container.stop();
}
}
Common Commands
Essential commands you'll use throughout the development lifecycle.
๐งช Testing Commands
# Run unit tests only
./mvnw test
# Run integration tests only
./mvnw integration-test
# Run all tests (unit + integration)
./mvnw verify
# Run specific test class
./mvnw test -Dtest=ClassName
# Run specific test method
./mvnw test -Dtest=ClassName#methodName
โจ Code Quality Commands
# Format code automatically
./mvnw spotless:apply
# Check code formatting
./mvnw spotless:check
# Compile with format check
./mvnw compile
๐ Development Commands
# Start JShell REPL
./mvnw jshell:run
# Create fat JAR
./mvnw package -Pshade
# Clean and rebuild
./mvnw clean compile
๐ฆ Package Management Commands
# Update dependencies
./mvnw versions:display-dependency-updates
# Install to local repository
./mvnw install
# Skip tests during build
./mvnw package -DskipTests
Code Quality & Formatting
Automated code quality enforcement with Spotless and best practices.
๐จ Code Formatting
# Apply formatting to all files
./mvnw spotless:apply
# Check formatting without changes
./mvnw spotless:check
# Format specific files
./mvnw spotless:apply -Dspotless.files=src/main/java/YourClass.java
Uses Google Java Format with AOSP style for consistent code formatting.
โ Quality Gates
Formatting is automatically checked during compilation:
./mvnw compile # Fails if code is not formatted
This ensures all code follows the same style conventions.
IDE Integration
IntelliJ IDEA Setup
- Install "google-java-format" plugin
- Go to Settings โ Other Settings โ google-java-format Settings
- Check "Enable google-java-format"
- Select "AOSP style"
- Enable "Reformat code" and "Optimize imports"
Java Version Management with jenv
If you have multiple Java versions installed, use jenv to manage them for this project.
๐ง Setup jenv (First Time)
# Install jenv (macOS with Homebrew)
brew install jenv
# Add to shell profile
echo 'export PATH="$HOME/.jenv/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(jenv init -)"' >> ~/.zshrc
# Restart shell or source profile
source ~/.zshrc
โ Configure Java 25
# Add Java 25 to jenv (adjust path as needed)
jenv add /path/to/java25
# List available versions
jenv versions
# Set Java 25 for this project
jenv local 25
# Verify version
java -version
๐ก Pro Tips
- The template works with any Java 21+ version, but Java 25 is recommended for full feature support
- jenv will create a
.java-versionfile in your project directory - This ensures everyone on your team uses the same Java version
- CI/CD pipeline is already configured with Oracle JDK 25
Interactive Development with JShell
Use JShell for rapid prototyping and interactive development.
๐ Starting JShell
# Start JShell with project classpath
./mvnw jshell:run
# Alternative: compile first, then start
./mvnw compile
./mvnw jshell:run
JShell starts with your project's compiled classes and dependencies on the classpath.
๐ก JShell Usage Examples
// Import your classes
import org.acme.*;
// Create instances and experiment
var func = new Function();
var input = new Function.Input(10, 20);
var result = func.add(input);
System.out.println(result);
// Test different scenarios interactively
/exit // Exit JShell
๐ฏ JShell Best Practices
- Use JShell for quick experimentation and API exploration
- Test edge cases before writing formal tests
- Prototype complex logic interactively
- Use
/helpfor available JShell commands - Save useful snippets to files with
/save filename.jsh
Maven Wrapper & Commands
Essential Maven commands using the wrapper for consistent builds across environments.
Build Lifecycle
./mvnw clean # Clean build artifacts
./mvnw compile # Compile main sources
./mvnw test-compile # Compile test sources
./mvnw test # Run unit tests
./mvnw package # Create JAR file
./mvnw verify # Run all tests + checks
./mvnw install # Install to local repo
Testing Commands
# Run specific test class
./mvnw test -Dtest=ClassName
# Run specific test method
./mvnw test -Dtest=ClassName#methodName
# Run tests with pattern
./mvnw test -Dtest="*ServiceTest"
# Skip tests during build
./mvnw package -DskipTests
Packaging & Profiles
# Create fat JAR with dependencies
./mvnw package -Pshade
# Clean and package
./mvnw clean package
# Install without running tests
./mvnw install -DskipTests
Analysis & Information
# Display dependency tree
./mvnw dependency:tree
# Check for updates
./mvnw versions:display-dependency-updates
# Display effective POM
./mvnw help:effective-pom
Modularization with JPMS
Java Platform Module System (JPMS) configuration for modern modular applications.
๐ฆ Main Module Configuration
// src/main/java/module-info.java
module org.acme {
exports org.acme;
// Add dependencies as needed
// requires java.logging;
// requires transitive java.base;
}
Configure your main module with exports and required dependencies.
๐งช Test Module Configuration
// src/test/java/module-info.java
open module org.acme.test {
requires org.acme;
requires org.junit.jupiter.api;
requires org.assertj.core;
requires net.jqwik.api;
}
Test module opens packages for reflection-based testing frameworks.
๐ฏ Modularization Best Practices
- Start with a simple module structure and evolve as needed
- Use
exportsto control API surface area - Prefer
requires transitivefor dependencies that are part of your API - Use
open modulein tests to allow reflection access - Consider splitting large applications into multiple modules
CI/CD with GitHub Actions
Automated build, test, and quality checks on every push to the main branch.
๐ Workflow Overview
name: Maven Build
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 2
- uses: actions/setup-java@v5
with:
distribution: "oracle"
java-version: 25
cache: "maven"
- run: ./mvnw verify
โ What Gets Validated
- Code Compilation - Java 25 syntax and compilation
- Code Formatting - Spotless formatting checks
- Unit Tests - All *Test.java classes
- Integration Tests - All *IT.java classes
- Package Creation - JAR file generation
๐ Optimization Features
- Maven Caching - Dependencies cached between runs
- Oracle JDK 25 - Latest Java version for CI
- Fast Checkout - Shallow clone with depth=2
- Parallel Execution - Tests run in parallel
- No Transfer Progress - Cleaner CI output
Performance & Optimization
Configuration and tips for optimal performance during development and production.
JVM Configuration
# .mvn/jvm.config
-Xmx2048m -Xms512m -Djava.awt.headless=true
Optimized heap settings and headless mode for better performance.
Maven Configuration
# .mvn/maven.config
-B
--fail-at-end
--no-transfer-progress
Batch mode and optimizations for faster, cleaner builds.
Parallel Testing
# junit-platform.properties
junit.jupiter.execution.parallel.enabled = true
junit.jupiter.execution.parallel.config.strategy = dynamic
Dynamic parallel test execution for faster feedback.
Build Optimization
# Skip tests during development
./mvnw compile -DskipTests
# Offline mode (if all deps cached)
./mvnw compile -o
# Multiple threads
./mvnw compile -T 4
Ready for Production Development?
Start building your Java 25 application with confidence using these proven practices and configurations.