Java › Generics

How would you implement a generic builder pattern with a self-referential generic type parameter (the 'curiously recurring generic pattern', <T extends Builder<T>>) to support fluent method chaining that correctly returns the actual subclass type in an inheritance hierarchy?

Advanced

Answer

A naive Builder base class returning `this` typed as the base Builder type breaks fluent chaining across a subclass hierarchy (a subclass-specific method called after a base-class method would return the base type, losing access to the subclass's own additional methods) -- the self-referential generic bound <T extends Builder<T>> lets the base class's chaining methods return T (the actual concrete subclass type, established when a subclass declares `class ConcreteBuilder extends Builder<ConcreteBuilder>`) rather than the base type, preserving full access to subclass-specific methods throughout the entire fluent chain regardless of how many base-class methods are called along the way.
public abstract class Builder<T extends Builder<T>> {
    protected String name;
    @SuppressWarnings("unchecked")
    public T withName(String name) { this.name = name; return (T) this; }  // returns concrete subclass type T
}

public class CarBuilder extends Builder<CarBuilder> {
    private int wheels;
    public CarBuilder withWheels(int wheels) { this.wheels = wheels; return this; }
}

CarBuilder car = new CarBuilder().withName("Tesla").withWheels(4);  // chaining works across base AND subclass methods seamlessly
Real-world example A configuration builder hierarchy with a shared base Builder class and multiple specialized subclasses (DatabaseConfigBuilder, CacheConfigBuilder) uses the self-referential generic bound to ensure fluent chains freely mix base-class and subclass-specific configuration methods in any order without ever losing access to subclass methods partway through the chain.

Common follow-ups: What happens if a subclass forgets to correctly parameterize itself (e.g., extends Builder<SomeOtherBuilder> by mistake)?;Why is the unchecked cast to (T) inside the base class considered safe in this specific, well-established pattern?