CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-immutables--immutables

Comprehensive Java annotation processing framework for generating immutable value objects, marshalers, repositories, and custom code generators with extensive integration support.

Pending
Overview
Eval results
Files

attributes.mddocs/

Attribute Customization

Annotations for customizing individual attributes including default values, lazy computation, validation, and parameter ordering. These annotations provide fine-grained control over how each attribute behaves in generated immutable classes.

Capabilities

Default Values

Provide default values for optional attributes in builders.

/**
 * Marks a method as providing a default value for an attribute.
 * The method body will be used as the default value in builders
 * when the attribute is not explicitly set.
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
@interface Value.Default {}

Usage Example:

import org.immutables.value.Value;
import java.time.Duration;

@Value.Immutable
public interface ServerConfig {
  String host();
  
  @Value.Default
  default int port() {
    return 8080;
  }
  
  @Value.Default
  default boolean ssl() {
    return false;
  }
  
  @Value.Default
  default Duration timeout() {
    return Duration.ofSeconds(30);
  }
}

// Usage - port, ssl, and timeout use defaults
ServerConfig config = ImmutableServerConfig.builder()
    .host("localhost")
    .build();

Derived Attributes

Computed attributes that are stored in fields for performance.

/**
 * Marks an attribute as derived/computed. The method implementation
 * provides the computation logic, and the result is cached in a field
 * for performance.
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
@interface Value.Derived {}

Usage Example:

import org.immutables.value.Value;
import java.time.LocalDate;
import java.time.Period;

@Value.Immutable
public interface Person {
  String firstName();
  String lastName();
  LocalDate birthDate();
  
  @Value.Derived
  default String fullName() {
    return firstName() + " " + lastName();
  }
  
  @Value.Derived
  default int age() {
    return Period.between(birthDate(), LocalDate.now()).getYears();
  }
}

// Derived attributes are computed once and cached
Person person = ImmutablePerson.builder()
    .firstName("Alice")
    .lastName("Smith")
    .birthDate(LocalDate.of(1990, 5, 15))
    .build();

String name = person.fullName(); // Computed once, cached
int age = person.age(); // Computed once, cached

Lazy Computation

Thread-safe lazy computed attributes for expensive operations.

/**
 * Marks an attribute as lazily computed. The computation is deferred
 * until first access and is thread-safe. Use for expensive computations
 * that may not always be needed.
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
@interface Value.Lazy {}

Usage Example:

import org.immutables.value.Value;
import java.util.List;

@Value.Immutable
public interface DataSet {
  List<Double> values();
  
  @Value.Lazy
  default double mean() {
    return values().stream()
        .mapToDouble(Double::doubleValue)
        .average()
        .orElse(0.0);
  }
  
  @Value.Lazy
  default double standardDeviation() {
    double mean = mean();
    return Math.sqrt(
        values().stream()
            .mapToDouble(v -> Math.pow(v - mean, 2))
            .average()
            .orElse(0.0)
    );
  }
}

// Expensive computations are deferred until needed
DataSet data = ImmutableDataSet.builder()
    .addValues(1.0, 2.0, 3.0, 4.0, 5.0)
    .build();

// Only computed when first accessed, then cached
double mean = data.mean();
double stdDev = data.standardDeviation();

Constructor Parameters

Control parameter ordering and inclusion in generated constructors.

/**
 * Marks an accessor method as a constructor parameter.
 * Controls the order of parameters in generated constructors
 * and factory methods.
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
@interface Value.Parameter {
  /** Order of parameter in constructor (lower values come first) */
  int order() default 0;
}

Usage Example:

@Value.Immutable
public interface Point3D {
  @Value.Parameter(order = 1)
  double x();
  
  @Value.Parameter(order = 2)
  double y();
  
  @Value.Parameter(order = 3)
  double z();
  
  // Not a constructor parameter
  @Value.Derived
  default double magnitude() {
    return Math.sqrt(x() * x() + y() * y() + z() * z());
  }
}

// Generated constructor respects parameter ordering
Point3D point = ImmutablePoint3D.of(1.0, 2.0, 3.0); // x, y, z order

Validation

Validation method invocation for instance validation.

/**
 * Marks a method as a validation method. The method will be called
 * during instance construction to validate the object state.
 * Should throw an exception if validation fails.
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)  
@interface Value.Check {}

Usage Example:

@Value.Immutable
public interface Rectangle {
  double width();
  double height();
  
  @Value.Check
  default void validate() {
    if (width() <= 0) {
      throw new IllegalArgumentException("Width must be positive");
    }
    if (height() <= 0) {
      throw new IllegalArgumentException("Height must be positive");  
    }
  }
  
  @Value.Derived
  default double area() {
    return width() * height();
  }
}

// Validation is automatically called during construction
try {
  Rectangle rect = ImmutableRectangle.builder()
      .width(-1.0)  // Invalid!
      .height(5.0)
      .build(); // Throws IllegalArgumentException
} catch (IllegalArgumentException e) {
  // Handle validation error
}

Auxiliary Attributes

Exclude attributes from equals, hashCode, and toString methods.

/**
 * Marks an attribute as auxiliary. Auxiliary attributes are excluded
 * from equals(), hashCode(), and toString() methods but are still
 * part of the immutable object.
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
@interface Value.Auxiliary {}

Usage Example:

@Value.Immutable
public interface CacheEntry {
  String key();
  String value();
  
  @Value.Auxiliary  // Not part of equality/hash
  Instant createdAt();
  
  @Value.Auxiliary  // Not part of equality/hash
  int accessCount();
}

// Two entries with same key/value are equal regardless of auxiliary fields
CacheEntry entry1 = ImmutableCacheEntry.builder()
    .key("user:123")
    .value("Alice")
    .createdAt(Instant.now())
    .accessCount(5)
    .build();

CacheEntry entry2 = ImmutableCacheEntry.builder()
    .key("user:123") 
    .value("Alice")
    .createdAt(Instant.now().minusSeconds(10)) // Different time
    .accessCount(2)  // Different count
    .build();

// Still equal because auxiliary fields are ignored
assert entry1.equals(entry2); // true
assert entry1.hashCode() == entry2.hashCode(); // true

Combining Annotations

Multiple attribute annotations can be combined for complex behavior:

@Value.Immutable
public interface ComplexType {
  String name();
  
  @Value.Default
  @Value.Parameter(order = 1)
  default String category() {
    return "default";
  }
  
  @Value.Lazy
  @Value.Auxiliary
  default String expensiveComputation() {
    // Expensive operation not included in equals/hash
    return performExpensiveCalculation();
  }
  
  @Value.Derived
  @Value.Check
  default String normalizedName() {
    String normalized = name().toLowerCase().trim();
    if (normalized.isEmpty()) {
      throw new IllegalArgumentException("Name cannot be empty");
    }
    return normalized;
  }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-immutables--immutables

docs

attributes.md

bean-style.md

code-generation.md

collections.md

core-immutable.md

index.md

integrations.md

json-marshaling.md

runtime-marshaling.md

styling.md

tile.json