The introduction of this User Guide covers the basic usage of AutoValue using a static factory method as your public creation API. But in many circumstances (such as those laid out in Effective Java, 2nd Edition Item 2), you may prefer to let your callers use a builder instead.
Fortunately, AutoValue can generate builder classes too! This page explains how. Note that we recommend reading and understanding the basic usage shown in the introduction first.
As explained in the introduction, the AutoValue concept is that you write an abstract value class, and AutoValue implements it. Builder generation works in the exact same way: you also create an abstract builder class, nesting it inside your abstract value class, and AutoValue generates implementations for both.
import com.google.auto.value.AutoValue;
@AutoValue
abstract class Animal {
abstract String name();
abstract int numberOfLegs();
static Builder builder() {
// The naming here will be different if you are using a nested class
// e.g. `return new AutoValue_OuterClass_InnerClass.Builder();`
return new AutoValue_Animal.Builder();
}
@AutoValue.Builder
abstract static class Builder {
abstract Builder setName(String value);
abstract Builder setNumberOfLegs(int value);
abstract Animal build();
}
}
Note that in real life, some classes and methods would presumably be public and have Javadoc. We're leaving these off in the User Guide only to keep the examples clean and short.
public void testAnimal() {
Animal dog = Animal.builder().setName("dog").setNumberOfLegs(4).build();
assertEquals("dog", dog.name());
assertEquals(4, dog.numberOfLegs());
// You probably don't need to write assertions like these; just illustrating.
assertTrue(
Animal.builder().setName("dog").setNumberOfLegs(4).build().equals(dog));
assertFalse(
Animal.builder().setName("cat").setNumberOfLegs(4).build().equals(dog));
assertFalse(
Animal.builder().setName("dog").setNumberOfLegs(2).build().equals(dog));
assertEquals("Animal{name=dog, numberOfLegs=4}", dog.toString());
}
For the Animal
example shown above, here is typical code AutoValue might
generate.
Be sure to put the static builder()
method directly in your value class (e.g.,
Animal
) and not the nested abstract Builder
class. That ensures that the
Animal
class is always initialized before Builder
. Otherwise you may be
exposing yourself to initialization-order problems.
- ... use (or not use)
set
prefixes? - ... use different names besides
builder()
/Builder
/build()
? - ... specify a default value for a property?
- ... initialize a builder to the same property values as an existing value instance
- ... include
with-
methods on my value class for creating slightly altered instances? - ... validate property values?
- ... normalize (modify) a property value at
build
time? - ... expose both a builder and a factory method?
- ... handle
Optional
properties? - ... use a collection-valued property?
- ... access nested builders while building?
- ... create a "step builder"?
- ... create a builder for something other than an
@AutoValue
? - ... use a different build method for a property?