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:
      - 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.

Support This Project

If you find this template useful, consider supporting its development!

Buy Me A Coffee