xref: /aosp_15_r20/external/auto/value/userguide/builders-howto.md (revision 1c2bbba85eccddce6de79cbbf1645fda32e723f0)
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*   ... [create a "step builder"?](#step)
36*   ... [create a builder for something other than an `@AutoValue`?](#autobuilder)
37*   ... [use a different build method for a
38    property?](#build_method)
39
40## <a name="beans"></a>... use (or not use) `set` prefixes?
41
42Just as you can choose whether to use JavaBeans-style names for property getters
43(`getFoo()` or just `foo()`) in your value class, you have the same choice for
44setters in builders too (`setFoo(value)` or just `foo(value)`). As with getters,
45you must use these prefixes consistently or not at all.
46
47Using `get`/`is` prefixes for getters and using the `set` prefix for setters are
48independent choices. For example, it is fine to use the `set` prefixes on all
49your builder methods, but omit the `get`/`is` prefixes from all your accessors.
50
51Here is the `Animal` example using `get` prefixes but not `set` prefixes:
52
53```java
54@AutoValue
55abstract class Animal {
56  abstract String getName();
57  abstract int getNumberOfLegs();
58
59  static Builder builder() {
60    return new AutoValue_Animal.Builder();
61  }
62
63  @AutoValue.Builder
64  abstract static class Builder {
65    abstract Builder name(String value);
66    abstract Builder numberOfLegs(int value);
67    abstract Animal build();
68  }
69}
70```
71
72## <a name="build_names"></a>... use different names besides `builder()`/`Builder`/`build()`?
73
74Use whichever names you like; AutoValue doesn't actually care.
75
76(We would gently recommend these names as conventional.)
77
78## <a name="default"></a>... specify a default value for a property?
79
80What should happen when a caller does not supply a value for a property before
81calling `build()`? If the property in question is [nullable](howto.md#nullable),
82it will simply default to `null` as you would expect. And if it is
83[Optional](#optional) it will default to an empty `Optional` as you might also
84expect. But if it isn't either of those things (including if it is a
85primitive-valued property, which *can't* be null), then `build()` will throw an
86unchecked exception. This includes collection properties, which must be given a
87value. They don't default to empty unless there is a
88[collection builder](#accumulate).
89
90But this requirement to supply a value presents a problem, since one of the main
91*advantages* of a builder in the first place is that callers can specify only
92the properties they care about!
93
94The solution is to provide a default value for such properties. Fortunately this
95is easy: just set it on the newly-constructed builder instance before returning
96it from the `builder()` method.
97
98Here is the `Animal` example with the default number of legs being 4:
99
100```java
101@AutoValue
102abstract class Animal {
103  abstract String name();
104  abstract int numberOfLegs();
105
106  static Builder builder() {
107    return new AutoValue_Animal.Builder()
108        .setNumberOfLegs(4);
109  }
110
111  @AutoValue.Builder
112  abstract static class Builder {
113    abstract Builder setName(String value);
114    abstract Builder setNumberOfLegs(int value);
115    abstract Animal build();
116  }
117}
118```
119
120Occasionally you may want to supply a default value, but only if the property is
121not set explicitly. This is covered in the section on
122[normalization](#normalize).
123
124## <a name="to_builder"></a>... initialize a builder to the same property values as an existing value instance
125
126Suppose your caller has an existing instance of your value class, and wants to
127change only one or two of its properties. Of course, it's immutable, but it
128would be convenient if they could easily get a `Builder` instance representing
129the same property values, which they could then modify and use to create a new
130value instance.
131
132To give them this ability, just add an abstract `toBuilder` method, returning
133your abstract builder type, to your value class. AutoValue will implement it.
134
135```java
136  public abstract Builder toBuilder();
137```
138
139## <a name="withers"></a>... include `with-` methods on my value class for creating slightly altered instances?
140
141This is a somewhat common pattern among immutable classes. You can't have
142setters, but you can have methods that act similarly to setters by returning a
143new immutable instance that has one property changed.
144
145If you're already using the builder option, you can add these methods by hand:
146
147```java
148@AutoValue
149public abstract class Animal {
150  public abstract String name();
151  public abstract int numberOfLegs();
152
153  public static Builder builder() {
154    return new AutoValue_Animal.Builder();
155  }
156
157  abstract Builder toBuilder();
158
159  public final Animal withName(String name) {
160    return toBuilder().setName(name).build();
161  }
162
163  @AutoValue.Builder
164  public abstract static class Builder {
165    public abstract Builder setName(String value);
166    public abstract Builder setNumberOfLegs(int value);
167    public abstract Animal build();
168  }
169}
170```
171
172Note that it's your free choice what to make public (`toBuilder`, `withName`,
173neither, or both).
174
175## <a name="validate"></a>... validate property values?
176
177Validating properties is a little less straightforward than it is in the
178[non-builder case](howto.md#validate).
179
180What you need to do is *split* your "build" method into two methods:
181
182*   the non-visible, abstract method that AutoValue implements
183*   and the visible, *concrete* method you provide, which calls the generated
184    method and performs validation.
185
186We recommend naming these methods `autoBuild` and `build`, but any names will
187work. It ends up looking like this:
188
189```java
190@AutoValue
191public abstract class Animal {
192  public abstract String name();
193  public abstract int numberOfLegs();
194
195  public static Builder builder() {
196    return new AutoValue_Animal.Builder();
197  }
198
199  @AutoValue.Builder
200  public abstract static class Builder {
201    public abstract Builder setName(String value);
202    public abstract Builder setNumberOfLegs(int value);
203
204    abstract Animal autoBuild();  // not public
205
206    public final Animal build() {
207      Animal animal = autoBuild();
208      Preconditions.checkState(animal.numberOfLegs() >= 0, "Negative legs");
209      return animal;
210    }
211  }
212}
213```
214
215## <a name="normalize"></a>... normalize (modify) a property value at `build` time?
216
217Suppose you want to convert the animal's name to lower case.
218
219You'll need to add a *getter* to your builder, as shown:
220
221```java
222@AutoValue
223public abstract class Animal {
224  public abstract String name();
225  public abstract int numberOfLegs();
226
227  public static Builder builder() {
228    return new AutoValue_Animal.Builder();
229  }
230
231  @AutoValue.Builder
232  public abstract static class Builder {
233    public abstract Builder setName(String value);
234    public abstract Builder setNumberOfLegs(int value);
235
236    abstract String name(); // must match method name in Animal
237
238    abstract Animal autoBuild(); // not public
239
240    public final Animal build() {
241      setName(name().toLowerCase());
242      return autoBuild();
243    }
244  }
245}
246```
247
248The getter in your builder must have the same signature as the abstract property
249accessor method in the value class. It will return the value that has been set
250on the `Builder`. If no value has been set for a
251non-[nullable](howto.md#nullable) property, `IllegalStateException` is thrown.
252
253Getters should generally only be used within the `Builder` as shown, so they are
254not public.
255
256<p id="optional-getter">As an alternative to returning the same type as the
257property accessor method, the builder getter can return an Optional wrapping of
258that type. This can be used if you want to supply a default, but only if the
259property has not been set. (The [usual way](#default) of supplying defaults
260means that the property always appears to have been set.) For example, suppose
261you wanted the default name of your Animal to be something like "4-legged
262creature", where 4 is the `numberOfLegs()` property. You might write this:
263
264```java
265@AutoValue
266public abstract class Animal {
267  public abstract String name();
268  public abstract int numberOfLegs();
269
270  public static Builder builder() {
271    return new AutoValue_Animal.Builder();
272  }
273
274  @AutoValue.Builder
275  public abstract static class Builder {
276    public abstract Builder setName(String value);
277    public abstract Builder setNumberOfLegs(int value);
278
279    abstract Optional<String> name();
280    abstract int numberOfLegs();
281
282    abstract Animal autoBuild(); // not public
283
284    public final Animal build() {
285      if (name().isEmpty()) {
286        setName(numberOfLegs() + "-legged creature");
287      }
288      return autoBuild();
289    }
290  }
291}
292```
293
294Notice that this will throw `IllegalStateException` if the `numberOfLegs`
295property hasn't been set either.
296
297The Optional wrapping can be any of the Optional types mentioned in the
298[section](#optional) on `Optional` properties. If your property has type `int`
299it can be wrapped as either `Optional<Integer>` or `OptionalInt`, and likewise
300for `long` and `double`.
301
302## <a name="both"></a>... expose *both* a builder *and* a factory method?
303
304If you use the builder option, AutoValue will not generate a visible constructor
305for the generated concrete value class. If it's important to offer your caller
306the choice of a factory method as well as the builder, then your factory method
307implementation will have to invoke the builder itself.
308
309## <a name="optional"></a>... handle `Optional` properties?
310
311Properties of type `Optional` benefit from special treatment. If you have a
312property of type `Optional<String>`, say, then it will default to an empty
313`Optional` without needing to [specify](#default) a default explicitly. And,
314instead of or as well as the normal `setFoo(Optional<String>)` method, you can
315have `setFoo(String)`. Then `setFoo(s)` is equivalent to
316`setFoo(Optional.of(s))`. (If it is `setFoo(@Nullable String)`, then `setFoo(s)`
317is equivalent to `setFoo(Optional.ofNullable(s))`.)
318
319Here, `Optional` means either [`java.util.Optional`] from Java (Java 8 or
320later), or [`com.google.common.base.Optional`] from Guava. Java 8 also
321introduced related classes in `java.util` called [`OptionalInt`],
322[`OptionalLong`], and [`OptionalDouble`]. You can use those in the same way. For
323example a property of type `OptionalInt` will default to `OptionalInt.empty()`
324and you can set it with either `setFoo(OptionalInt)` or `setFoo(int)`.
325
326```java
327@AutoValue
328public abstract class Animal {
329  public abstract Optional<String> name();
330
331  public static Builder builder() {
332    return new AutoValue_Animal.Builder();
333  }
334
335  @AutoValue.Builder
336  public abstract static class Builder {
337    // You can have either or both of these two methods:
338    public abstract Builder setName(Optional<String> value);
339    public abstract Builder setName(String value);
340    public abstract Animal build();
341  }
342}
343```
344
345[`java.util.Optional`]: https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html
346[`com.google.common.base.Optional`]: https://guava.dev/releases/snapshot/api/docs/com/google/common/base/Optional.html
347[`OptionalDouble`]: https://docs.oracle.com/javase/8/docs/api/java/util/OptionalDouble.html
348[`OptionalInt`]: https://docs.oracle.com/javase/8/docs/api/java/util/OptionalInt.html
349[`OptionalLong`]: https://docs.oracle.com/javase/8/docs/api/java/util/OptionalLong.html
350
351## <a name="collection"></a>... use a collection-valued property?
352
353Value objects should be immutable, so if a property of one is a collection then
354that collection should be immutable too. We recommend using Guava's [immutable
355collections] to make that explicit. AutoValue's builder support includes a few
356special arrangements to make this more convenient.
357
358In the examples here we use `ImmutableSet`, but the same principles apply to all
359of Guava's immutable collection types, like `ImmutableList`,
360`ImmutableMultimap`, and so on.
361
362We recommend using the immutable type (like `ImmutableSet<String>`) as your
363actual property type. However, it can be a pain for callers to always have to
364construct `ImmutableSet` instances to pass into your builder. So AutoValue
365allows your builder method to accept an argument of any type that
366`ImmutableSet.copyOf` accepts.
367
368If our `Animal` acquires an `ImmutableSet<String>` that is the countries it
369lives in, that can be set from a `Set<String>` or a `Collection<String>` or an
370`Iterable<String>` or a `String[]` or any other compatible type. You can even
371offer multiple choices, as in this example:
372
373```java
374@AutoValue
375public abstract class Animal {
376  public abstract String name();
377  public abstract int numberOfLegs();
378  public abstract ImmutableSet<String> countries();
379
380  public static Builder builder() {
381    return new AutoValue_Animal.Builder();
382  }
383
384  @AutoValue.Builder
385  public abstract static class Builder {
386    public abstract Builder setName(String value);
387    public abstract Builder setNumberOfLegs(int value);
388    public abstract Builder setCountries(Set<String> value);
389    public abstract Builder setCountries(String... value);
390    public abstract Animal build();
391  }
392}
393```
394
395[immutable collections]: https://github.com/google/guava/wiki/ImmutableCollectionsExplained
396
397### <a name="accumulate"></a>... let my builder *accumulate* values for a collection-valued property (not require them all at once)?
398
399Instead of defining a setter for an immutable collection `foos`, you can define
400a method `foosBuilder()` that returns the associated builder type for that
401collection. In this example, we have an `ImmutableSet<String>` which can be
402built using the `countriesBuilder()` method:
403
404```java
405@AutoValue
406public abstract class Animal {
407  public abstract String name();
408  public abstract int numberOfLegs();
409  public abstract ImmutableSet<String> countries();
410
411  public static Builder builder() {
412    return new AutoValue_Animal.Builder();
413  }
414
415  @AutoValue.Builder
416  public abstract static class Builder {
417    public abstract Builder setName(String value);
418    public abstract Builder setNumberOfLegs(int value);
419    public abstract ImmutableSet.Builder<String> countriesBuilder();
420    public abstract Animal build();
421  }
422}
423```
424
425The name of this method must be exactly the property name (`countries` here)
426followed by the string `Builder`. Even if the properties follow the
427`getCountries()` convention, the builder method must be `countriesBuilder()`
428and not `getCountriesBuilder()`.
429
430It's also possible to have a method like `countriesBuilder` with a single
431argument, provided that the `Builder` class has a public constructor or a
432static `builder` method, with one parameter that the argument can be assigned
433to. For example, if `countries()` were an `ImmutableSortedSet<String>` and you
434wanted to supply a `Comparator` to `ImmutableSortedSet.Builder`, you could
435write:
436
437```java
438    public abstract ImmutableSortedSet.Builder<String>
439        countriesBuilder(Comparator<String> comparator);
440```
441
442That works because `ImmutableSortedSet.Builder` has a constructor that
443accepts a `Comparator` parameter.
444
445You may notice a small problem with these examples: the caller can no longer
446create their instance in a single chained statement:
447
448```java
449  // This DOES NOT work!
450  Animal dog = Animal.builder()
451      .setName("dog")
452      .setNumberOfLegs(4)
453      .countriesBuilder()
454          .add("Guam")
455          .add("Laos")
456      .build();
457```
458
459Instead they are forced to hold the builder itself in a temporary variable:
460
461```java
462  // This DOES work... but we have to "break the chain"!
463  Animal.Builder builder = Animal.builder()
464      .setName("dog")
465      .setNumberOfLegs(4);
466  builder.countriesBuilder()
467      .add("Guam")
468      .add("Laos");
469  Animal dog = builder.build();
470```
471
472One solution for this problem is just below.
473
474### <a name="add"></a>... accumulate values for a collection-valued property, without "breaking the chain"?
475
476Another option is to keep `countriesBuilder()` itself non-public, and only use
477it to implement a public `addCountry` method:
478
479```java
480@AutoValue
481public abstract class Animal {
482  public abstract String name();
483  public abstract int numberOfLegs();
484  public abstract ImmutableSet<String> countries();
485
486  public static Builder builder() {
487    return new AutoValue_Animal.Builder();
488  }
489
490  @AutoValue.Builder
491  public abstract static class Builder {
492    public abstract Builder setName(String value);
493    public abstract Builder setNumberOfLegs(int value);
494
495    abstract ImmutableSet.Builder<String> countriesBuilder();
496    public final Builder addCountry(String value) {
497      countriesBuilder().add(value);
498      return this;
499    }
500
501    public abstract Animal build();
502  }
503}
504```
505
506Now the caller can do this:
507
508```java
509  // This DOES work!
510  Animal dog = Animal.builder()
511      .setName("dog")
512      .setNumberOfLegs(4)
513      .addCountry("Guam")
514      .addCountry("Laos") // however many times needed
515      .build();
516```
517
518### <a name="collection_both"></a>... offer both accumulation and set-at-once methods for the same collection-valued property?
519
520Yes, you can provide both methods, letting your caller choose the style they
521prefer.
522
523The same caller can mix the two styles only in limited ways; once `foosBuilder`
524has been called, any subsequent call to `setFoos` will throw an unchecked
525exception. On the other hand, calling `setFoos` first is okay; a later call to
526`foosBuilder` will return a builder already populated with the
527previously-supplied elements.
528
529## <a name="nested_builders"></a>... access nested builders while building?
530
531Often a property of an `@AutoValue` class is itself an immutable class,
532perhaps another `@AutoValue`. In such cases your builder can expose a builder
533for that nested class. This is very similar to exposing a builder for a
534collection property, as described [earlier](#accumulate).
535
536Suppose the `Animal` class has a property of type `Species`:
537
538```java
539@AutoValue
540public abstract class Animal {
541  public abstract String name();
542  public abstract Species species();
543
544  public static Builder builder() {
545    return new AutoValue_Animal.Builder();
546  }
547
548  @AutoValue.Builder
549  public abstract static class Builder {
550    public abstract Builder setName(String name);
551    public abstract Species.Builder speciesBuilder();
552    public abstract Animal build();
553  }
554}
555
556@AutoValue
557public abstract class Species {
558  public abstract String genus();
559  public abstract String epithet();
560
561  public static Builder builder() {
562    return new AutoValue_Species.Builder();
563  }
564
565  @AutoValue.Builder
566  public abstract static class Builder {
567    public abstract Builder setGenus(String genus);
568    public abstract Builder setEpithet(String epithet);
569    public abstract Species build();
570  }
571}
572```
573
574Now you can access the builder of the nested `Species` while you are building
575the `Animal`:
576
577```java
578  Animal.Builder catBuilder = Animal.builder()
579      .setName("cat");
580  catBuilder.speciesBuilder()
581      .setGenus("Felis")
582      .setEpithet("catus");
583  Animal cat = catBuilder.build();
584```
585
586Although the nested class in the example (`Species`) is also an `@AutoValue`
587class, it does not have to be. For example, it could be a [protobuf]. The
588requirements are:
589
590* The nested class must have a way to make a new builder. This can be
591  `new Species.Builder()`, or `Species.builder()`, or `Species.newBuilder()`.
592
593* There must be a way to build an instance from the builder: `Species.Builder`
594  must have a method `Species build()`.
595
596* If there is a need to convert `Species` back into its builder, then `Species`
597  must have a method `Species.Builder toBuilder()`.
598
599  In the example, if `Animal` has an abstract [`toBuilder()`](#to_builder)
600  method then `Species` must also have a `toBuilder()` method. That also applies
601  if there is an abstract `setSpecies` method in addition to the
602  `speciesBuilder` method.
603
604  As an alternative to having a method `Species.Builder toBuilder()` in
605  `Species`, `Species.Builder` can have a method called `addAll` or `putAll`
606  that accepts an argument of type `Species`. This is how AutoValue handles
607  `ImmutableSet` for example. `ImmutableSet` does not have a `toBuilder()`
608  method, but `ImmutableSet.Builder` does have an `addAll` method that accepts
609  an `ImmutableSet`. So given `ImmutableSet<String> strings`, we can achieve the
610  effect of `strings.toBuilder()` by doing:
611
612  ```
613  ImmutableSet.Builder<String> builder = ImmutableSet.builder();
614  builder.addAll(strings);
615  ```
616
617There are no requirements on the name of the builder class. Instead of
618`Species.Builder`, it could be `Species.Factory` or `SpeciesBuilder`.
619
620If `speciesBuilder()` is never called then the final `species()` property will
621be set as if by `speciesBuilder().build()`. In the example, that would result
622in an exception because the required properties of `Species` have not been set.
623
624## <a name="step"></a>... create a "step builder"?
625
626A [_step builder_](http://rdafbn.blogspot.com/2012/07/step-builder-pattern_28.html)
627is a collection of builder interfaces that take you step by step through the
628setting of each of a list of required properties. This means you can be sure at
629compile time that all the properties are set before you build, at the expense of
630some extra code and a bit less flexibility.
631
632Here is an example:
633
634```java
635@AutoValue
636public abstract class Stepped {
637  public abstract String foo();
638  public abstract String bar();
639  public abstract int baz();
640
641  public static FooStep builder() {
642    return new AutoValue_Stepped.Builder();
643  }
644
645  public interface FooStep {
646    BarStep setFoo(String foo);
647  }
648
649  public interface BarStep {
650    BazStep setBar(String bar);
651  }
652
653  public interface BazStep {
654    Build setBaz(int baz);
655  }
656
657  public interface Build {
658    Stepped build();
659  }
660
661  @AutoValue.Builder
662  abstract static class Builder implements FooStep, BarStep, BazStep, Build {}
663}
664```
665
666It might be used like this:
667
668```java
669Stepped stepped = Stepped.builder().setFoo("foo").setBar("bar").setBaz(3).build();
670```
671
672The idea is that the only way to build an instance of `Stepped`
673is to go through the steps imposed by the `FooStep`, `BarStep`, and
674`BazStep` interfaces to set the properties in order, with a final build step.
675
676Once you have set the `baz` property there is nothing else to do except build,
677so you could also combine the `setBaz` and `build` methods like this:
678
679```java
680  ...
681
682  public interface BazStep {
683    Stepped setBazAndBuild(int baz);
684  }
685
686  @AutoValue.Builder
687  abstract static class Builder implements FooStep, BarStep, BazStep {
688    abstract Builder setBaz(int baz);
689    abstract Stepped build();
690
691    @Override
692    public Stepped setBazAndBuild(int baz) {
693      return setBaz(baz).build();
694    }
695  }
696```
697
698## <a name="autobuilder"></a> ... create a builder for something other than an `@AutoValue`?
699
700Sometimes you want to make a builder like the kind described here, but have it
701build something other than an `@AutoValue` class, or even call a static method.
702In that case you can use `@AutoBuilder`. See
703[its documentation](autobuilder.md).
704
705Sometimes you want to use a different build method for your property. This is
706especially applicable for `ImmutableMap`, which has two different build methods.
707`builder.buildOrThrow()` is used as the default build method for AutoValue. You
708might prefer to use `builder.buildKeepingLast()` instead, so if the same key is
709put more than once then the last value is retained rather than throwing an
710exception. AutoValue doesn't currently have a way to request this, but here is a
711workaround if you need it. Let's say you have a class like this:
712
713```java
714  @AutoValue
715  public abstract class Foo {
716    public abstract ImmutableMap<Integer, String> map();
717    ...
718
719    @AutoValue.Builder
720    public abstract static class Builder {
721      public abstract ImmutableMap.Builder<Integer, String> mapBuilder();
722      public abstract Foo build();
723    }
724  }
725```
726
727Instead, you could write this:
728
729```java
730  @AutoValue
731  public abstract class Foo {
732    public abstract ImmutableMap<Integer, String> map();
733
734    // #start
735    // Needed only if your class has toBuilder() method
736    public Builder toBuilder() {
737      Builder builder = autoToBuilder();
738      builder.mapBuilder().putAll(map());
739      return builder;
740    }
741
742    abstract Builder autoToBuilder(); // not public
743    // #end
744
745    @AutoValue.Builder
746    public abstract static class Builder {
747
748      private final ImmutableMap.Builder<Integer, String> mapBuilder = ImmutableMap.builder();
749
750      public ImmutableMap.Builder<Integer, String> mapBuilder() {
751        return mapBuilder;
752      }
753
754      abstract Builder setMap(ImmutableMap<Integer, String> map); // not public
755
756      abstract Foo autoBuild(); // not public
757
758      public Foo build() {
759        setMap(mapBuilder.buildKeepingLast());
760        return autoBuild();
761      }
762    }
763  }
764```
765
766[protobuf]: https://developers.google.com/protocol-buffers/docs/reference/java-generated#builders
767