Skip to main content

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.

1

Start Development

./mvnw compile  # Compile and format check
./mvnw test     # Run unit tests
2

Write Code & Tests

Write your implementation in src/main/java and corresponding tests in src/test/java

3

Continuous Testing

./mvnw test -Dtest=YourTestClass  # Run specific test
./mvnw spotless:apply             # Format code
4

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();
    }
}

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

  1. Install "google-java-format" plugin
  2. Go to Settings โ†’ Other Settings โ†’ google-java-format Settings
  3. Check "Enable google-java-format"
  4. Select "AOSP style"
  5. Enable "Reformat code" and "Optimize imports"

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 /help for 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 exports to control API surface area
  • Prefer requires transitive for dependencies that are part of your API
  • Use open module in 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:
      - name: "Checkout Sources"
        uses: actions/checkout@v5
        with:
          fetch-depth: 2

      - name: "Setup JDK"
        uses: actions/setup-java@v5
        with:
          distribution: "oracle"
          java-version: 25
          cache: "maven"

      - name: "Build with 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.