• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# How do I... (Builder edition)
2
3
4This page answers common how-to questions that may come up when using AutoValue
5**with the builder option**. You should read and understand [AutoValue with
6builders](builders.md) first.
7
8If you are not using a builder, see [Introduction](index.md) and
9[How do I...](howto.md) instead.
10
11## Contents
12
13How do I...
14
15*   ... [use (or not use) `set` **prefixes**?](#beans)
16*   ... [use different **names** besides
17    `builder()`/`Builder`/`build()`?](#build_names)
18*   ... [specify a **default** value for a property?](#default)
19*   ... [initialize a builder to the same property values as an **existing**
20    value instance](#to_builder)
21*   ... [include `with-` methods on my value class for creating slightly
22    **altered** instances?](#withers)
23*   ... [**validate** property values?](#validate)
24*   ... [**normalize** (modify) a property value at `build` time?](#normalize)
25*   ... [expose **both** a builder and a factory method?](#both)
26*   ... [handle `Optional` properties?](#optional)
27*   ... [use a **collection**-valued property?](#collection)
28    *   ... [let my builder **accumulate** values for a collection-valued
29        property (not require them all at once)?](#accumulate)
30    *   ... [accumulate values for a collection-valued property, without
31        **"breaking the chain"**?](#add)
32    *   ... [offer **both** accumulation and set-at-once methods for the same
33        collection-valued property?](#collection_both)
34*   ... [access nested builders while building?](#nested_builders)
35
36## <a name="beans"></a>... use (or not use) `set` prefixes?
37
38Just as you can choose whether to use JavaBeans-style names for property getters
39(`getFoo()` or just `foo()`) in your value class, you have the same choice for
40setters in builders too (`setFoo(value)` or just `foo(value)`). As with getters,
41you must use these prefixes consistently or not at all.
42
43Using `get`/`is` prefixes for getters and using the `set` prefix for setters are
44independent choices. For example, it is fine to use the `set` prefixes on all
45your builder methods, but omit the `get`/`is` prefixes from all your accessors.
46
47Here is the `Animal` example using `get` prefixes but not `set` prefixes:
48
49```java
50@AutoValue
51abstract class Animal {
52  abstract String getName();
53  abstract int getNumberOfLegs();
54
55  static Builder builder() {
56    return new AutoValue_Animal.Builder();
57  }
58
59  @AutoValue.Builder
60  abstract static class Builder {
61    abstract Builder name(String value);
62    abstract Builder numberOfLegs(int value);
63    abstract Animal build();
64  }
65}
66```
67
68## <a name="build_names"></a>... use different names besides `builder()`/`Builder`/`build()`?
69
70Use whichever names you like; AutoValue doesn't actually care.
71
72(We would gently recommend these names as conventional.)
73
74## <a name="default"></a>... specify a default value for a property?
75
76What should happen when a caller does not supply a value for a property before
77calling `build()`? If the property in question is [nullable](howto.md#nullable),
78it will simply default to `null` as you would expect. And if it is
79[Optional](#optional) it will default to an empty `Optional` as you might also
80expect. But if it isn't either of those things (including if it is a
81primitive-valued property, which *can't* be null), then `build()` will throw an
82unchecked exception.
83
84But this presents a problem, since one of the main *advantages* of a builder in
85the first place is that callers can specify only the properties they care about!
86
87The solution is to provide a default value for such properties. Fortunately this
88is easy: just set it on the newly-constructed builder instance before returning
89it from the `builder()` method.
90
91Here is the `Animal` example with the default number of legs being 4:
92
93```java
94@AutoValue
95abstract class Animal {
96  abstract String name();
97  abstract int numberOfLegs();
98
99  static Builder builder() {
100    return new AutoValue_Animal.Builder()
101        .setNumberOfLegs(4);
102  }
103
104  @AutoValue.Builder
105  abstract static class Builder {
106    abstract Builder setName(String value);
107    abstract Builder setNumberOfLegs(int value);
108    abstract Animal build();
109  }
110}
111```
112
113Occasionally you may want to supply a default value, but only if the property is
114not set explicitly. This is covered in the section on
115[normalization](#normalize).
116
117## <a name="to_builder"></a>... initialize a builder to the same property values as an existing value instance
118
119Suppose your caller has an existing instance of your value class, and wants to
120change only one or two of its properties. Of course, it's immutable, but it
121would be convenient if they could easily get a `Builder` instance representing
122the same property values, which they could then modify and use to create a new
123value instance.
124
125To give them this ability, just add an abstract `toBuilder` method, returning
126your abstract builder type, to your value class. AutoValue will implement it.
127
128```java
129  public abstract Builder toBuilder();
130```
131
132## <a name="withers"></a>... include `with-` methods on my value class for creating slightly altered instances?
133
134This is a somewhat common pattern among immutable classes. You can't have
135setters, but you can have methods that act similarly to setters by returning a
136new immutable instance that has one property changed.
137
138If you're already using the builder option, you can add these methods by hand:
139
140```java
141@AutoValue
142public abstract class Animal {
143  public abstract String name();
144  public abstract int numberOfLegs();
145
146  public static Builder builder() {
147    return new AutoValue_Animal.Builder();
148  }
149
150  abstract Builder toBuilder();
151
152  public Animal withName(String name) {
153    return toBuilder().setName(name).build();
154  }
155
156  @AutoValue.Builder
157  public abstract static class Builder {
158    public abstract Builder setName(String value);
159    public abstract Builder setNumberOfLegs(int value);
160    public abstract Animal build();
161  }
162}
163```
164
165Note that it's your free choice what to make public (`toBuilder`, `withName`,
166neither, or both).
167
168## <a name="validate"></a>... validate property values?
169
170Validating properties is a little less straightforward than it is in the
171[non-builder case](howto.md#validate).
172
173What you need to do is *split* your "build" method into two methods:
174
175*   the non-visible, abstract method that AutoValue implements
176*   and the visible, *concrete* method you provide, which calls the generated
177    method and performs validation.
178
179We recommend naming these methods `autoBuild` and `build`, but any names will
180work. It ends up looking like this:
181
182```java
183@AutoValue
184public abstract class Animal {
185  public abstract String name();
186  public abstract int numberOfLegs();
187
188  public static Builder builder() {
189    return new AutoValue_Animal.Builder();
190  }
191
192  @AutoValue.Builder
193  public abstract static class Builder {
194    public abstract Builder setName(String value);
195    public abstract Builder setNumberOfLegs(int value);
196
197    abstract Animal autoBuild();  // not public
198
199    public Animal build() {
200      Animal animal = autoBuild();
201      Preconditions.checkState(animal.numberOfLegs() >= 0, "Negative legs");
202      return animal;
203    }
204  }
205}
206```
207
208## <a name="normalize"></a>... normalize (modify) a property value at `build` time?
209
210Suppose you want to convert the animal's name to lower case.
211
212You'll need to add a *getter* to your builder, as shown:
213
214```java
215@AutoValue
216public abstract class Animal {
217  public abstract String name();
218  public abstract int numberOfLegs();
219
220  public static Builder builder() {
221    return new AutoValue_Animal.Builder();
222  }
223
224  @AutoValue.Builder
225  public abstract static class Builder {
226    public abstract Builder setName(String value);
227    public abstract Builder setNumberOfLegs(int value);
228
229    abstract String name(); // must match method name in Animal
230
231    abstract Animal autoBuild(); // not public
232
233    public Animal build() {
234      setName(name().toLowerCase());
235      return autoBuild();
236    }
237  }
238}
239```
240
241The getter in your builder must have the same signature as the abstract property
242accessor method in the value class. It will return the value that has been set
243on the `Builder`. If no value has been set for a
244non-[nullable](howto.md#nullable) property, `IllegalStateException` is thrown.
245
246Getters should generally only be used within the `Builder` as shown, so they are
247not public.
248
249As an alternative to returning the same type as the property accessor method,
250the builder getter can return an Optional wrapping of that type. This can be
251used if you want to supply a default, but only if the property has not been set.
252(The [usual way](#default) of supplying defaults means that the property always
253appears to have been set.) For example, suppose you wanted the default name of
254your Animal to be something like "4-legged creature", where 4 is the
255`numberOfLegs()` property. You might write this:
256
257```java
258@AutoValue
259public abstract class Animal {
260  public abstract String name();
261  public abstract int numberOfLegs();
262
263  public static Builder builder() {
264    return new AutoValue_Animal.Builder();
265  }
266
267  @AutoValue.Builder
268  public abstract static class Builder {
269    public abstract Builder setName(String value);
270    public abstract Builder setNumberOfLegs(int value);
271
272    abstract Optional<String> name();
273    abstract int numberOfLegs();
274
275    abstract Animal autoBuild(); // not public
276
277    public Animal build() {
278      if (!name().isPresent()) {
279        setName(numberOfLegs() + "-legged creature");
280      }
281      return autoBuild();
282    }
283  }
284}
285```
286
287Notice that this will throw `IllegalStateException` if the `numberOfLegs`
288property hasn't been set either.
289
290The Optional wrapping can be any of the Optional types mentioned in the
291[section](#optional) on `Optional` properties. If your property has type `int`
292it can be wrapped as either `Optional<Integer>` or `OptionalInt`, and likewise
293for `long` and `double`.
294
295## <a name="both"></a>... expose *both* a builder *and* a factory method?
296
297If you use the builder option, AutoValue will not generate a visible constructor
298for the generated concrete value class. If it's important to offer your caller
299the choice of a factory method as well as the builder, then your factory method
300implementation will have to invoke the builder itself.
301
302## <a name="optional"></a>... handle `Optional` properties?
303
304Properties of type `Optional` benefit from special treatment. If you have a
305property of type `Optional<String>`, say, then it will default to an empty
306`Optional` without needing to [specify](#default) a default explicitly. And,
307instead of or as well as the normal `setFoo(Optional<String>)` method, you can
308have `setFoo(String)`. Then `setFoo(s)` is equivalent to
309`setFoo(Optional.of(s))`.
310
311Here, `Optional` means either [`java.util.Optional`] from Java (Java 8 or
312later), or [`com.google.common.base.Optional`] from Guava. Java 8 also
313introduced related classes in `java.util` called [`OptionalInt`],
314[`OptionalLong`], and [`OptionalDouble`]. You can use those in the same way. For
315example a property of type `OptionalInt` will default to `OptionalInt.empty()`
316and you can set it with either `setFoo(OptionalInt)` or `setFoo(int)`.
317
318```java
319@AutoValue
320public abstract class Animal {
321  public abstract Optional<String> name();
322
323  public static Builder builder() {
324    return new AutoValue_Animal.Builder();
325  }
326
327  @AutoValue.Builder
328  public abstract static class Builder {
329    // You can have either or both of these two methods:
330    public abstract Builder setName(Optional<String> value);
331    public abstract Builder setName(String value);
332    public abstract Animal build();
333  }
334}
335```
336
337[`java.util.Optional`]: https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html
338[`com.google.common.base.Optional`]: https://guava.dev/releases/snapshot/api/docs/com/google/common/base/Optional.html
339[`OptionalDouble`]: https://docs.oracle.com/javase/8/docs/api/java/util/OptionalDouble.html
340[`OptionalInt`]: https://docs.oracle.com/javase/8/docs/api/java/util/OptionalInt.html
341[`OptionalLong`]: https://docs.oracle.com/javase/8/docs/api/java/util/OptionalLong.html
342
343## <a name="collection"></a>... use a collection-valued property?
344
345Value objects should be immutable, so if a property of one is a collection then
346that collection should be immutable too. We recommend using Guava's [immutable
347collections] to make that explicit. AutoValue's builder support includes a few
348special arrangements to make this more convenient.
349
350In the examples here we use `ImmutableSet`, but the same principles apply to all
351of Guava's immutable collection types, like `ImmutableList`,
352`ImmutableMultimap`, and so on.
353
354We recommend using the immutable type (like `ImmutableSet<String>`) as your
355actual property type. However, it can be a pain for callers to always have to
356construct `ImmutableSet` instances to pass into your builder. So AutoValue
357allows your builder method to accept an argument of any type that
358`ImmutableSet.copyOf` accepts.
359
360If our `Animal` acquires an `ImmutableSet<String>` that is the countries it
361lives in, that can be set from a `Set<String>` or a `Collection<String>` or an
362`Iterable<String>` or a `String[]` or any other compatible type. You can even
363offer multiple choices, as in this example:
364
365```java
366@AutoValue
367public abstract class Animal {
368  public abstract String name();
369  public abstract int numberOfLegs();
370  public abstract ImmutableSet<String> countries();
371
372  public static Builder builder() {
373    return new AutoValue_Animal.Builder();
374  }
375
376  @AutoValue.Builder
377  public abstract static class Builder {
378    public abstract Builder setName(String value);
379    public abstract Builder setNumberOfLegs(int value);
380    public abstract Builder setCountries(Set<String> value);
381    public abstract Builder setCountries(String... value);
382    public abstract Animal build();
383  }
384}
385```
386
387[immutable collections]: https://github.com/google/guava/wiki/ImmutableCollectionsExplained
388
389### <a name="accumulate"></a>... let my builder *accumulate* values for a collection-valued property (not require them all at once)?
390
391Instead of defining a setter for an immutable collection `foos`, you can define
392a method `foosBuilder()` that returns the associated builder type for that
393collection. In this example, we have an `ImmutableSet<String>` which can be
394built using the `countriesBuilder()` method:
395
396```java
397@AutoValue
398public abstract class Animal {
399  public abstract String name();
400  public abstract int numberOfLegs();
401  public abstract ImmutableSet<String> countries();
402
403  public static Builder builder() {
404    return new AutoValue_Animal.Builder();
405  }
406
407  @AutoValue.Builder
408  public abstract static class Builder {
409    public abstract Builder setName(String value);
410    public abstract Builder setNumberOfLegs(int value);
411    public abstract ImmutableSet.Builder<String> countriesBuilder();
412    public abstract Animal build();
413  }
414}
415```
416
417The name of this method must be exactly the property name (`countries` here)
418followed by the string `Builder`. Even if the properties follow the
419`getCountries()` convention, the builder method must be `countriesBuilder()`
420and not `getCountriesBuilder()`.
421
422You may notice a small problem with this example: the caller can no longer
423create their instance in a single chained statement:
424
425```java
426  // This DOES NOT work!
427  Animal dog = Animal.builder()
428      .setName("dog")
429      .setNumberOfLegs(4)
430      .countriesBuilder()
431          .add("Guam")
432          .add("Laos")
433      .build();
434```
435
436Instead they are forced to hold the builder itself in a temporary variable:
437
438```java
439  // This DOES work... but we have to "break the chain"!
440  Animal.Builder builder = Animal.builder()
441      .setName("dog")
442      .setNumberOfLegs(4);
443  builder.countriesBuilder()
444      .add("Guam")
445      .add("Laos");
446  Animal dog = builder.build();
447```
448
449One solution for this problem is just below.
450
451### <a name="add"></a>... accumulate values for a collection-valued property, without "breaking the chain"?
452
453Another option is to keep `countriesBuilder()` itself non-public, and only use
454it to implement a public `addCountry` method:
455
456```java
457@AutoValue
458public abstract class Animal {
459  public abstract String name();
460  public abstract int numberOfLegs();
461  public abstract ImmutableSet<String> countries();
462
463  public static Builder builder() {
464    return new AutoValue_Animal.Builder();
465  }
466
467  @AutoValue.Builder
468  public abstract static class Builder {
469    public abstract Builder setName(String value);
470    public abstract Builder setNumberOfLegs(int value);
471
472    abstract ImmutableSet.Builder<String> countriesBuilder();
473    public Builder addCountry(String value) {
474      countriesBuilder().add(value);
475      return this;
476    }
477
478    public abstract Animal build();
479  }
480}
481```
482
483Now the caller can do this:
484
485```java
486  // This DOES work!
487  Animal dog = Animal.builder()
488      .setName("dog")
489      .setNumberOfLegs(4)
490      .addCountry("Guam")
491      .addCountry("Laos") // however many times needed
492      .build();
493```
494
495### <a name="collection_both"></a>... offer both accumulation and set-at-once methods for the same collection-valued property?
496
497Yes, you can provide both methods, letting your caller choose the style they
498prefer.
499
500The same caller can mix the two styles only in limited ways; once `foosBuilder`
501has been called, any subsequent call to `setFoos` will throw an unchecked
502exception. On the other hand, calling `setFoos` first is okay; a later call to
503`foosBuilder` will return a builder already populated with the
504previously-supplied elements.
505
506## <a name="nested_builders"></a>... access nested builders while building?
507
508Often a property of an `@AutoValue` class is itself an immutable class,
509perhaps another `@AutoValue`. In such cases your builder can expose a builder
510for that nested class. This is very similar to exposing a builder for a
511collection property, as described [earlier](#accumulate).
512
513Suppose the `Animal` class has a property of type `Species`:
514
515```java
516@AutoValue
517public abstract class Animal {
518  public abstract String name();
519  public abstract Species species();
520
521  public static Builder builder() {
522    return new AutoValue_Animal.Builder();
523  }
524
525  @AutoValue.Builder
526  public abstract static class Builder {
527    public abstract Builder setName(String name);
528    public abstract Species.Builder speciesBuilder();
529    public abstract Animal build();
530  }
531}
532
533@AutoValue
534public abstract class Species {
535  public abstract String genus();
536  public abstract String epithet();
537
538  public static Builder builder() {
539    return new AutoValue_Species.Builder();
540  }
541
542  @AutoValue.Builder
543  public abstract static class Builder {
544    public abstract Builder setGenus(String genus);
545    public abstract Builder setEpithet(String epithet);
546    public abstract Species build();
547  }
548}
549```
550
551Now you can access the builder of the nested `Species` while you are building
552the `Animal`:
553
554```java
555  Animal.Builder catBuilder = Animal.builder()
556      .setName("cat");
557  catBuilder.speciesBuilder()
558      .setGenus("Felis")
559      .setEpithet("catus");
560  Animal cat = catBuilder.build();
561```
562
563Although the nested class in the example (`Species`) is also an `@AutoValue`
564class, it does not have to be. For example, it could be a [protobuf]. The
565requirements are:
566
567* The nested class must have a way to make a new builder. This can be
568  `new Species.Builder()`, or `Species.builder()`, or `Species.newBuilder()`.
569
570* There must be a way to build an instance from the builder: `Species.Builder`
571  must have a method `Species build()`.
572
573* If there is a need to convert `Species` back into its builder, then `Species`
574  must have a method `Species.Builder toBuilder()`.
575
576  In the example, if `Animal` has an abstract [`toBuilder()`](#to_builder)
577  method then `Species` must also have a `toBuilder()` method. That also applies
578  if there is an abstract `setSpecies` method in addition to the
579  `speciesBuilder` method.
580
581  As an alternative to having a method `Species.Builder toBuilder()` in
582  `Species`, `Species.Builder` can have a method called `addAll` or `putAll`
583  that accepts an argument of type `Species`. This is how AutoValue handles
584  `ImmutableSet` for example. `ImmutableSet` does not have a `toBuilder()`
585  method, but `ImmutableSet.Builder` does have an `addAll` method that accepts
586  an `ImmutableSet`. So given `ImmutableSet<String> strings`, we can achieve the
587  effect of `strings.toBuilder()` by doing:
588
589  ```
590  ImmutableSet.Builder<String> builder = ImmutableSet.builder();
591  builder.addAll(strings);
592  ```
593
594There are no requirements on the name of the builder class. Instead of
595`Species.Builder`, it could be `Species.Factory` or `SpeciesBuilder`.
596
597If `speciesBuilder()` is never called then the final `species()` property will
598be set as if by `speciesBuilder().build()`. In the example, that would result
599in an exception because the required properties of `Species` have not been set.
600
601
602[protobuf]: https://developers.google.com/protocol-buffers/docs/reference/java-generated#builders
603