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