Skip to content

Record Builder

pawel_labaj edited this page Aug 2, 2023 · 11 revisions

Builders are a useful pattern that allow you to specify a set of optional parameters when creating a record, which can improve readability and reduce the need for constructor overloading.

AutoRecord provides support for generating builders using the Randgalt/record-builder library.

Enabling Builder Generation

To enable builder generation for a given interface, simply add the @AutoRecord.Options(withBuilder = true) annotation to it. This will cause AutoRecord to add the @RecordBuilder annotation to generated record and this will cause generating a builder in a next round of annotation processing.

The generated record includes a static builder() method, which return a new builder instance. It includes also a toBuilder() method, which returns a builder instance with the values from the existing record.

Example interface and generated record

Here's an example interface:

@AutoRecord
@AutoRecord.Options(withBuilder = true)
interface Person {
    String name();
    int age();
}

Here's the corresponding generated record that demonstrates builder generation:

@Generated("pl.com.labaj.autorecord.AutoRecord")
@GeneratedWithAutoRecord
@RecordBuilder
@RecordBuilder.Options(
        addClassRetainedGenerated = true
)
record PersonRecord(String name, int age) implements Person {
    PersonRecord {
        requireNonNull(name, "name must not be null");
    }

    static PersonRecordBuilder builder() {
        return PersonRecordBuilder.builder();
    }

    PersonRecordBuilder toBuilder() {
        return PersonRecordBuilder.builder(this);
    }
}

You can create the record instance with using builder:

PersonRecord person = PersonRecord.builder()
    .name("Joe")
    .age(25)
    .build();

PersonRecord olderPerson = person.toBuilder()
    .age(50)
    .build();

It is recommended to provide in your interface:

  • a factory method with a clear and descriptive name to get the record builder
  • an abstract toBuilder() method that is implemented in the record

Here is an example of what it might look like:

@AutoRecord
@AutoRecord.Options(withBuilder = true)
interface Person {
    String name();
    int age();

    static PersonRecordBuilder builder() {
        return PersonRecord.builder();
    }

    PersonRecordBuilder toBuilder();
}

Customizing Builder Generation

If you want to customize the builder generation process, you can add the RecordBuilder.Options annotation to the interface.

Example interface and generated record

Here's an example interface:

@AutoRecord
@AutoRecord.Options(withBuilder = true)
@RecordBuilder.Options(suffix = "_Creator")
interface PersonB {
    String name();
    int age();
}

Here's the corresponding generated record that demonstrates builder generation:

@Generated("pl.com.labaj.autorecord.AutoRecord")
@GeneratedWithAutoRecord
@RecordBuilder
@RecordBuilder.Options(
        addClassRetainedGenerated = true,
        suffix = "_Creator"
)
record PersonBRecord(String name, int age) implements PersonB {
    PersonBRecord {
        requireNonNull(name, "name must not be null");
    }

    static PersonBRecord_Creator builder() {
        return PersonBRecord_Creator.builder();
    }

    PersonBRecord_Creator toBuilder() {
        return PersonBRecord_Creator.builder(this);
    }
}
📝 Note
It is recommended to use builder() and toBuilder() methods from an interface or generated record and not from generated builder.

For more information, refer to the RecordBuilder library's documentation.

Clone this wiki locally