SkillAgentSearch skills...

Default4j

Default parameter values for Java via annotation processing

Install / Use

/learn @reugn/Default4j

README

default4j

Build Maven Central javadoc

Default parameter values for Java via annotation processing.

Java doesn't natively support default parameter values like Scala, Kotlin, or Python. This library fills that gap by generating helper code at compile time.

Table of Contents

Features

  • Default parameters for methods — call greet() instead of greet("World", "Hello")
  • Named parameters — set only what you need: .host("prod").timeout(30).call()
  • Constructor & record factoriesUserDefaults.create("Alice") with sensible defaults
  • Works with external types — generate defaults for third-party classes you can't modify
  • Extensive compile-time validation — catch errors early with helpful messages and typo suggestions
  • Compile-time only — no runtime dependencies, no reflection, just plain Java

Comparison with Other Libraries

Feature Comparison

| Feature | default4j | Lombok | Immutables | AutoValue | record-builder | |---------|-----------|--------|------------|-----------|----------------| | Primary Focus | Default values | Boilerplate reduction | Immutable objects | Value types | Record builders | | Method Defaults | ✅ Full support | ❌ | ❌ | ❌ | ❌ | | Constructor Defaults | ✅ Full support | ⚠️ Limited | ⚠️ Via builder | ⚠️ Via builder | ⚠️ Via builder | | Named Parameters | ✅ Built-in | ❌ | ✅ Via builder | ✅ Via builder | ✅ Via builder | | Record Support | ✅ Native | ⚠️ Partial | ✅ | ❌ | ✅ Native | | External Types | ✅ @IncludeDefaults | ❌ | ❌ | ❌ | ✅ | | Factory Methods | ✅ @DefaultFactory | ❌ | ❌ | ❌ | ❌ | | Field References | ✅ @DefaultValue(field=...) | ❌ | ❌ | ❌ | ❌ |

Technical Comparison

| Aspect | default4j | Lombok | Immutables | AutoValue | record-builder | |--------|-----------|--------|------------|-----------|----------------| | Approach | Annotation Processing | Bytecode Modification | Annotation Processing | Annotation Processing | Annotation Processing | | Runtime Dependency | None | None | Optional | None | None | | IDE Plugin Required | No | Yes | No | No | No | | Compile-time Validation | ✅ Extensive | ⚠️ Limited | ✅ | ✅ | ✅ | | Debuggable Output | ✅ Plain Java | ⚠️ Complex | ✅ Plain Java | ✅ Plain Java | ✅ Plain Java | | Java Version | 17+ | 8+ | 8+ | 8+ | 16+ |

When to Use Each

| Library | Best For | |--------------------|------------------------------------------------------------------------------------------| | default4j | Adding default parameters to existing code, method defaults, Python/Kotlin-like defaults | | Lombok | Reducing boilerplate (getters, setters, equals, toString), quick prototyping | | Immutables | Complex immutable objects with many optional fields, serialization support | | AutoValue | Simple value types, Google ecosystem integration | | record-builder | Adding builders to records, withers for records |

Complementary Usage

default4j can work alongside other libraries:

// With Lombok - use Lombok for boilerplate, default4j for defaults
@Getter @Setter
public class Config {
    @WithDefaults
    public Config(@DefaultValue("localhost") String host) { ... }
}

// With record-builder - use record-builder for withers, default4j for factory defaults
@RecordBuilder  // Generates withHost(), withPort() etc.
@WithDefaults   // Generates ConfigDefaults.create() with defaults
public record Config(
    @DefaultValue("localhost") String host,
    @DefaultValue("8080") int port) {}

Key Differentiators

default4j is unique in providing:

  1. Method-level defaults — No other library supports default values for regular method parameters
  2. Unified syntax — Same @DefaultValue works for methods, constructors, and records
  3. True default values — Unlike builders, you get actual default parameters (omit trailing args)
  4. Factory method defaults@DefaultFactory for computed/lazy default values
  5. Field reference defaults@DefaultValue(field="CONSTANT") for static constants
  6. External type defaults@IncludeDefaults for third-party classes you can't modify

When to Use Constructor Defaults

Java allows inline field initialization, but constructor defaults solve problems inline initialization can't:

| Use Case | Inline Defaults | default4j | |----------|----------------|-----------| | Records & Immutables | ❌ Not possible | ✅ Full support | | Factory Methods | ❌ Manual boilerplate | ✅ Auto-generated | | Third-Party Classes | ❌ Can't modify source | ✅ @IncludeDefaults | | Computed Defaults | ❌ No method calls | ✅ @DefaultFactory | | Builder Pattern | ❌ Manual implementation | ✅ named=true | | Self-Documenting API | ❌ Defaults hidden in code | ✅ Visible in annotations |

Best for: Records, immutable classes, factory patterns, external types, computed/dynamic values.

When inline is simpler: Mutable classes with simple literal defaults that don't need factory methods.


Installation

Maven

<dependency>
    <groupId>io.github.reugn</groupId>
    <artifactId>default4j</artifactId>
    <version>${version}</version>
</dependency>

Gradle

implementation 'io.github.reugn:default4j:${version}'
annotationProcessor 'io.github.reugn:default4j:${version}'

Quick Start

import io.github.reugn.default4j.annotation.*;

@WithDefaults
public class Config {
    public Config(
            @DefaultValue("localhost") String host,
            @DefaultValue("8080") int port) {
        // ...
    }
}

// Usage - generated ConfigDefaults class:
Config c1 = ConfigDefaults.create();              // host="localhost", port=8080
Config c2 = ConfigDefaults.create("example.com"); // host="example.com", port=8080

Usage Guide

1. Method Defaults

Generate overloaded static methods that omit trailing parameters with defaults.

public class Greeter {
    @WithDefaults
    public String greet(
            @DefaultValue("World") String name,
            @DefaultValue("Hello") String greeting) {
        return greeting + ", " + name + "!";
    }
}

Generated usage:

Greeter g = new Greeter();
GreeterDefaults.greet(g);                  // "Hello, World!"
GreeterDefaults.greet(g, "Alice");         // "Hello, Alice!"
GreeterDefaults.greet(g, "Alice", "Hi");   // "Hi, Alice!"

2. Named Parameters

Use named = true to generate a fluent builder that allows skipping any parameter, not just trailing ones.

public class Database {
    @WithDefaults(named = true)
    public Connection connect(
            @DefaultValue("localhost") String host,
            @DefaultValue("5432") int port,
            @DefaultValue("postgres") String user) {
        return createConnection(host, port, user);
    }
}

Generated usage:

Database db = new Database();

// Skip port, set only host and user
DatabaseDefaults.connect(db)
    .host("prod.example.com")
    .user("admin")
    .call();

// Use all defaults
DatabaseDefaults.connect(db).call();

3. Constructor Defaults

Generate factory methods for constructors with default parameters.

public class User {
    @WithDefaults
    public User(
            String name,
            @DefaultValue("user@example.com") String email,
            @DefaultValue("USER") String role) {
        // ...
    }
}

Generated usage:

User u1 = UserDefaults.create("Alice");                     // Default email & role
User u2 = UserDefaults.create("Bob", "bob@test.com");       // Default role
User u3 = UserDefaults.create("Carol", "c@x.com", "ADMIN"); // All specified

Named mode for constructors:

public class User {
    @WithDefaults(named = true)
    public User(String name, @DefaultValue("USER") String role) {
        // ...
    }
}

// Skip to any parameter
User u = UserDefaults.create()
    .name("Alice")
    .build();  // role uses default

4. Class-Level Annotation

Apply @WithDefaults to a class to generate helpers for all constructors and methods that have @DefaultValue or @DefaultFactory parameters.

@WithDefaults
public class Service {
    // Constructor with defaults -> factory methods generated
    public Service(
            @DefaultValue("default") String name,
            @DefaultValue("100") int value) {
        // ...
    }
    
    // Method with defaults -> helper methods generated
    public void process(@DefaultValue("INFO") String level) {
        // ...
    }
}

Generated usage:

Service s = ServiceDefaults.create();   // All constructor defaults
ServiceDefaults.process(s);             // Method with default level

With options:

@WithDefaults(named = true, methodName = "builder")
public class AppConfig {
    public AppConfig(
            @DefaultValue("localhost") String ho
View on GitHub
GitHub Stars35
CategoryDevelopment
Updated19d ago
Forks1

Languages

Java

Security Score

95/100

Audited on Mar 13, 2026

No findings