Skip to content
This repository was archived by the owner on Oct 16, 2024. It is now read-only.

Commit b22e232

Browse files
authored
#306 Specialised support for lists of buildable objects
Combine existing support for list properties and buildable properties. A list of buildable objects will now get: * versions of all add methods that accept Builders * late calling of the build() methods * cascading of buildPartial() * getter and mutator exposing a list of builders rather than a list of values * lazy conversion of immutable instances to builders
2 parents 8ac52b0 + e3ee9c3 commit b22e232

File tree

10 files changed

+3173
-264
lines changed

10 files changed

+3173
-264
lines changed

README.md

+59-3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ _Automatic generation of the Builder pattern for Java 1.8+_
2626
- [Converting from `@Nullable`](#converting-from-nullable)
2727
- [Collections and Maps](#collections-and-maps)
2828
- [Nested buildable types](#nested-buildable-types)
29+
- [Lists of buildable types](#lists-of-buildable-types)
30+
- [Disabling buildable lists](#disabling-buildable-lists)
2931
- [Custom toString method](#custom-tostring-method)
3032
- [Custom functional interfaces](#custom-functional-interfaces)
3133
- [Builder construction](#builder-construction)
@@ -38,7 +40,9 @@ _Automatic generation of the Builder pattern for Java 1.8+_
3840
- [Gradle](#gradle)
3941
- [Eclipse](#eclipse)
4042
- [IntelliJ](#intellij)
41-
- [Upgrading from v1](#upgrading-from-v1)
43+
- [Release notes](#release-notes)
44+
- [2.1—Lists of buildable types](#21lists-of-buildable-types)
45+
- [Upgrading from v1](#upgrading-from-v1)
4246
- [Troubleshooting](#troubleshooting)
4347
- [Troubleshooting javac](#troubleshooting-javac)
4448
- [Troubleshooting Eclipse](#troubleshooting-eclipse)
@@ -437,6 +441,51 @@ Project project = new Project.Builder()
437441
[Consumer]: https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html
438442

439443

444+
### Lists of buildable types
445+
446+
FreeBuilder has special support for lists of buildable types, too. It maintains
447+
a list of builders, to allow elements of the list to be built incrementally. (For
448+
better performance, if given a built instance for the list, it will lazily convert
449+
it to a Builder on demand. This may cause problems if your buildable types
450+
continue to be mutable after construction; to avoid unpredictable aliasing,
451+
we recommend disabling buildable list support, as described below.)
452+
453+
A list of buildable properties called 'owners' would generate:
454+
455+
| Method | Description |
456+
|:------:| ----------- |
457+
| `addOwners(Person element)` | Appends `element` to the collection of owners. Throws a NullPointerException if element is null. The element may be lazily converted to/from a Builder. |
458+
| `addOwners(Person.Builder builder)` | Appends the value built by `builder` to the collection of owners. Throws a NullPointerException if builder is null. Only a copy of the builder will be stored; changes made to it after this method returns will have no effect on the list. The copied builder's `build()` method will not be called immediately, so if this builder's state is not legal, you will not get failures until you build the final immutable object. |
459+
| `addOwners(Person... elements)` | Appends all `elements` to the collection of owners. Throws a NullPointerException if elements, or any of the values it holds, is null. Each element may be lazily converted to/from a Builder. |
460+
| `addOwners(Person.Builder... builders)` | Appends the values built by `builders` to the collection of owners. Throws a NullPointerException if builders, or any of the values it holds, is null. Only copies of the builders will be stored, and `build()` methods will not be called immediately. |
461+
| `addAllOwners(​Iterable<Person> elements)`<br>`addAllOwners(​Stream<Person> elements)`<br>`addAllOwners(​Spliterator<Person> elements)` | Appends all `elements` to the collection of owners. Throws a NullPointerException if elements, or any of the values it holds, is null. Each element may be lazily converted to/from a Builder. |
462+
| `addAllBuildersOfOwners(​Iterable<Person.Builder> builders)`<br>`addAllBuildersOfOwners(​Stream<Person.Builder> builders)`<br>`addAllBuildersOfOwners(​Spliterator<Person.Builder> builders)` | Appends the values built by `builders` to the collection of owners. Throws a NullPointerException if builders, or any of the values it holds, is null. Only copies of the builders will be stored, and `build()` methods will not be called immediately. |
463+
| `mutateOwners(​Consumer<? super List<Person.Builder>> mutator)` | Invokes the [Consumer] `mutator` with the list of owner builders. Throws a NullPointerException if `mutator` is null. As `mutator` is a void consumer, any value returned from a lambda will be ignored, so be careful not to call pure functions like [stream()] expecting the returned collection to replace the existing collection. |
464+
| `clearOwners()` | Removes all elements from the collection of owners, leaving it empty. |
465+
| `buildersOfOwners()` | Returns an unmodifiable view of the list of owner builders. Changes to the list held by the builder will be reflected in the view, and changes made to any of the returned builders will be reflected in the final list of owners. |
466+
467+
Note that `mutateOwners` and `buildersOfOwners` are the only methods which can cause lazy convertion of an inserted value to a Builder, and then only upon accessing the element, so avoid these actions if possible to avoid unexpected performance hits.
468+
469+
#### Disabling buildable lists
470+
471+
You can force FreeBuilder to use vanilla list support, rather than converting elements
472+
to/from Builders under the hood, by declaring a vanilla getter in the Builder. For
473+
instance, to force `owners` to drop Builder support:
474+
475+
```java
476+
class Builder extends Foo_Builder {
477+
@Override
478+
public List<Person> owners() {
479+
// Disable FreeBuilder's lazy conversion to/from Person.Builder by declaring
480+
// a non-Builder-compatible getter.
481+
return super.owners();
482+
}
483+
}
484+
```
485+
486+
FreeBuilder will now generate the methods described in [Collections and Maps](#collections-and-maps).
487+
488+
440489
### Custom toString method
441490

442491
FreeBuilder will only generate toString, hashCode and equals methods if they are left abstract, so to customise them, just implement them.
@@ -672,9 +721,16 @@ directory** setting) and select **Mark Directory As > Generated Sources Root**.
672721
[IntelliJ 14.0.3 documentation]: http://www.jetbrains.com/idea/webhelp/configuring-annotation-processing.html
673722
[Auto Issue #106]: https://github.com/google/auto/issues/106
674723

724+
Release notes
725+
-------------
675726

676-
Upgrading from v1
677-
-----------------
727+
### 2.1—Lists of buildable types
728+
729+
FreeBuilder 2.1 adds more extensive API customization for [lists of buildable types](#lists-of-buildable-types), storing Builder instances internally until build is called, cascading buildPartial automatically, and adding overloads accepting Builder instances.
730+
731+
This is a behavioural and, for the get and mutate methods, a non-binary-backwards-compatible change. If you have existing properties that you do not want this to affect, see [disabling buildable lists](#disabling-buildable-lists) for instructions on restoring the 2.0 behaviour on a case-by-case basis.
732+
733+
### Upgrading from v1
678734

679735
There are three API-breaking changes between v1 and v2 of FreeBuilder:
680736

src/main/java/org/inferred/freebuilder/processor/Analyser.java

+1
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ public static class CannotGenerateCodeException extends Exception { }
9696
*/
9797
private static final List<PropertyCodeGenerator.Factory> PROPERTY_FACTORIES = ImmutableList.of(
9898
new NullableProperty.Factory(), // Must be first, as no other factory supports nulls
99+
new BuildableListProperty.Factory(), // Must be before ListProperty
99100
new ListProperty.Factory(),
100101
new SetProperty.Factory(),
101102
new SortedSetProperty.Factory(),

0 commit comments

Comments
 (0)