Generated immutable value classes for Java 8+ using annotation processing
—
AutoValue can generate builder classes that provide a fluent API for constructing value objects, especially useful for classes with many properties or optional fields.
@AutoValue
public abstract class Person {
public abstract String name();
public abstract int age();
public abstract Optional<String> email();
public static Builder builder() {
return new AutoValue_Person.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder name(String name);
public abstract Builder age(int age);
public abstract Builder email(String email);
public abstract Person build();
}
}Person person = Person.builder()
.name("Alice")
.age(30)
.email("alice@example.com")
.build();
// Optional properties can be omitted
Person personWithoutEmail = Person.builder()
.name("Bob")
.age(25)
.build();Set default values in the builder factory method:
@AutoValue
public abstract class Configuration {
public abstract String host();
public abstract int port();
public abstract boolean ssl();
public abstract int timeoutMs();
public static Builder builder() {
return new AutoValue_Configuration.Builder()
.host("localhost")
.port(8080)
.ssl(false)
.timeoutMs(5000);
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder host(String host);
public abstract Builder port(int port);
public abstract Builder ssl(boolean ssl);
public abstract Builder timeoutMs(int timeoutMs);
public abstract Configuration build();
}
}Usage with defaults:
Configuration defaultConfig = Configuration.builder().build();
// host=localhost, port=8080, ssl=false, timeoutMs=5000
Configuration customConfig = Configuration.builder()
.host("api.example.com")
.ssl(true)
.build();
// host=api.example.com, port=8080, ssl=true, timeoutMs=5000Builders provide convenience methods for adding to collections:
@AutoValue
public abstract class Team {
public abstract String name();
public abstract ImmutableList<String> members();
public abstract ImmutableSet<String> skills();
public static Builder builder() {
return new AutoValue_Team.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder name(String name);
// Collection setters
public abstract Builder members(Iterable<String> members);
public abstract Builder skills(Iterable<String> skills);
// Individual item adders (generated automatically)
public abstract Builder addMember(String member);
public abstract Builder addSkill(String skill);
// Multiple item adders (generated automatically)
public abstract Builder addAllMembers(Iterable<String> members);
public abstract Builder addAllSkills(Iterable<String> skills);
public abstract Team build();
}
}Usage:
Team team = Team.builder()
.name("Backend Team")
.addMember("Alice")
.addMember("Bob")
.addAllMembers(Arrays.asList("Charlie", "Diana"))
.addSkill("Java")
.addAllSkills(Arrays.asList("Spring", "PostgreSQL"))
.build();Generate a builder from an existing instance:
@AutoValue
public abstract class Person {
public abstract String name();
public abstract int age();
public abstract Optional<String> email();
// toBuilder method
public abstract Builder toBuilder();
public static Builder builder() {
return new AutoValue_Person.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder name(String name);
public abstract Builder age(int age);
public abstract Builder email(String email);
public abstract Person build();
}
}Usage:
Person original = Person.builder()
.name("Alice")
.age(30)
.build();
Person updated = original.toBuilder()
.age(31)
.email("alice@example.com")
.build();Build nested objects directly in the builder:
@AutoValue
public abstract class Address {
public abstract String street();
public abstract String city();
public static Builder builder() {
return new AutoValue_Address.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder street(String street);
public abstract Builder city(String city);
public abstract Address build();
}
}
@AutoValue
public abstract class Person {
public abstract String name();
public abstract Address address();
public static Builder builder() {
return new AutoValue_Person.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder name(String name);
public abstract Builder address(Address address);
// Property builder for nested object
public abstract Address.Builder addressBuilder();
public abstract Person build();
}
}Usage:
Person person = Person.builder()
.name("Alice")
.addressBuilder()
.street("123 Main St")
.city("Springfield")
.and() // Returns to parent builder
.build();
// Or build separately
Address address = Address.builder()
.street("456 Oak Ave")
.city("Springfield")
.build();
Person person2 = Person.builder()
.name("Bob")
.address(address)
.build();Add validation to the build() method:
@AutoValue
public abstract class ValidatedPerson {
public abstract String name();
public abstract int age();
public abstract String email();
public static Builder builder() {
return new AutoValue_ValidatedPerson.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder name(String name);
public abstract Builder age(int age);
public abstract Builder email(String email);
abstract ValidatedPerson autoBuild(); // Package-private build method
public ValidatedPerson build() {
ValidatedPerson person = autoBuild();
checkArgument(!person.name().isEmpty(), "Name cannot be empty");
checkArgument(person.age() >= 0, "Age must be non-negative");
checkArgument(person.email().contains("@"), "Invalid email format");
return person;
}
private static void checkArgument(boolean condition, String message) {
if (!condition) {
throw new IllegalArgumentException(message);
}
}
}
}Handle optional properties elegantly:
@AutoValue
public abstract class Product {
public abstract String name();
public abstract double price();
public abstract Optional<String> description();
public abstract Optional<String> category();
public static Builder builder() {
return new AutoValue_Product.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder name(String name);
public abstract Builder price(double price);
public abstract Builder description(String description);
public abstract Builder category(String category);
// Optional overloads for convenience
public abstract Builder description(Optional<String> description);
public abstract Builder category(Optional<String> category);
public abstract Product build();
}
}Usage:
Product basic = Product.builder()
.name("Widget")
.price(19.99)
.build(); // Optional fields will be empty
Product detailed = Product.builder()
.name("Advanced Widget")
.price(39.99)
.description("A very advanced widget")
.category("Electronics")
.build();Builders work with generic types:
@AutoValue
public abstract class Container<T> {
public abstract T value();
public abstract String label();
public static <T> Builder<T> builder() {
return new AutoValue_Container.Builder<>();
}
@AutoValue.Builder
public abstract static class Builder<T> {
public abstract Builder<T> value(T value);
public abstract Builder<T> label(String label);
public abstract Container<T> build();
}
}Usage:
Container<String> stringContainer = Container.<String>builder()
.value("Hello")
.label("Greeting")
.build();
Container<Integer> intContainer = Container.<Integer>builder()
.value(42)
.label("Answer")
.build();Builders can be used with inheritance hierarchies:
public abstract class Animal {
public abstract String name();
public abstract int age();
}
@AutoValue
public abstract class Dog extends Animal {
public abstract String breed();
public abstract boolean trained();
public static Builder builder() {
return new AutoValue_Dog.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder name(String name);
public abstract Builder age(int age);
public abstract Builder breed(String breed);
public abstract Builder trained(boolean trained);
public abstract Dog build();
}
}Install with Tessl CLI
npx tessl i tessl/maven-com-google-auto-value--auto-value