From 63aefa41e432a050496e9f96c6ce570dde276e18 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Mon, 26 Jan 2015 08:46:41 +0100 Subject: documentation for @Singular. --- website/features/Builder.html | 172 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 website/features/Builder.html (limited to 'website/features/Builder.html') diff --git a/website/features/Builder.html b/website/features/Builder.html new file mode 100644 index 00000000..e99f8525 --- /dev/null +++ b/website/features/Builder.html @@ -0,0 +1,172 @@ + + + + + + + + @Builder +
+
+
+ +

@Builder

+ +
+

Since

+

+ @Builder was introduced as experimental feature in lombok v0.12.0. +

+ @Builder gained @Singular support and was promoted to the main lombok package since lombok v1.16.0. +

+
+
+

Overview

+

+ The @Builder annotation produces complex builder APIs for your classes. +

+ @Builder lets you automatically produce the code required to have your class be instantiable with code such as:
+ Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build(); +

+ @Builder can be placed on a class, or on a constructor, or on a static method. While the "on a class" and "on a constructor" + mode are the most common use-case, @Builder is most easily explained with the "static method" use-case. +

+ A static method annotated with @Builder (from now on called the target) causes the following 7 things to be generated:

    +
  • An inner static class named FooBuilder, with the same type arguments as the static method (called the builder).
  • +
  • In the builder: One private non-static non-final field for each parameter of the target.
  • +
  • In the builder: A package private no-args empty constructor.
  • +
  • In the builder: A 'setter'-like method for each parameter of the target: It has the same type as that parameter and the same name. + It returns the builder itself, so that the setter calls can be chained, as in the above example.
  • +
  • In the builder: A build() method which calls the static method, passing in each field. It returns the same type that the + target returns.
  • +
  • In the builder: A sensible toString() implementation.
  • +
  • In the class containing the target: A builder() method, which creates a new instance of the builder.
  • +
+ Each listed generated element will be silently skipped if that element already exists (disregarding parameter counts and looking only at names). This + includes the builder itself: If that class already exists, lombok will simply start injecting fields and methods inside this already existing + class, unless of course the fields / methods to be injected already exist. You may not put any other method (or constructor) generating lombok annotation + on a builder class though; for example, you can not put @EqualsAndHashCode on the builder class. +

+ @Builder can generate so-called 'singular' methods for collection parameters/fields. These take 1 element instead of an entire list, and add the + element to the list. For example: Person.builder().job("Mythbusters").job("Unchained Reaction").build(); would result in the List<String> jobs + field to have 2 strings in it. To get this behaviour, the field/parameter needs to be annotated with @Singular. The feature has its own documentation. +

+ Now that the "static method" mode is clear, putting a @Builder annotation on a constructor functions similarly; effectively, + constructors are just static methods that have a special syntax to invoke them: Their 'return type' is the class they construct, and their + type parameters are the same as the type parameters of the class itself. +

+ Finally, applying @Builder to a class is as if you added @AllArgsConstructor(access = AccessLevel.PACKAGE) to the class and applied the + @Builder annotation to this all-args-constructor. This only works if you haven't written any explicit constructors yourself. If you do have an + explicit constructor, put the @Builder annotation on the constructor instead of on the class. +

+ The name of the builder class is FoobarBuilder, where Foobar is the simplified, title-cased form of the return type of the + target - that is, the name of your type for @Builder on constructors and types, and the name of the return type for @Builder + on static methods. For example, if @Builder is applied to a class named com.yoyodyne.FancyList<T>, then the builder name will be + FancyListBuilder<T>. If @Builder is applied to a static method that returns void, the builder will be named + VoidBuilder. +

+ The configurable aspects of builder are:

    +
  • The builder's class name (default: return type + 'Builder')
  • +
  • The build() method's name (default: "build")
  • +
  • The builder() method's name (default: "builder")
  • +
+ Example usage where all options are changed from their defaults:
+ @Builder(builderClassName = "HelloWorldBuilder", buildMethodName = "execute", builderMethodName = "helloWorld")
+

+
+
+

@Singular

+

+ By annotating one of the parameters (if annotating a static method or constructor with @Builder) or fields (if annotating a class with @Builder) with the + @Singular annotation, lombok will treat that builder node as a collection, and it generates 2 'adder' methods instead of a 'setter' method. One which adds a single element to the collection, and one + which adds all elements of another collection to the collection. No setter to just set the collection (replacing whatever was already added) will be generated. These 'singular' builders + are very complicated in order to guarantee the following properties: +

    +
  • When invoking build(), the produced collection will be immutable.
  • +
  • Repeatedly invoking build() works fine and does not corrupt any of the collections already generated.
  • +
  • Calling one of the 'adder' methods after invoking build() does not modify any already generated objects, and, if build() is later called again, +
  • The produced collection will be compacted to the smallest feasible format while remaining efficient.
  • +
+

+ @Singular can only be applied to collection types for which lombok has a recipe to produce the singular methods. Currently, the supported types are: +

    +
  • java.util:
      +
    • Collection and List (backed by a compacted unmodifiable ArrayList in the general case).
    • +
    • Set, SortedSet, and NavigableSet (backed by a smartly sized unmodifiable HashSet or TreeSet in the general case).
    • +
    • Map, SortedMap, and NavigableMap (backed by a smartly sized unmodifiable HashMap or TreeMap in the general case).
    • +
  • +
  • Guava's com.google.common.collect:
      +
    • ImmutableCollection and ImmutableList (backed by the builder feature of ImmutableList).
    • +
    • ImmutableSet and ImmutableSortedSet (backed by the builder feature of those types).
    • +
    • ImmutableMap, ImmutableBiMap, and ImmutableSortedMap (backed by the builder feature of those types).
    • +
  • +
+

+ If your identifiers are written in common english, lombok assumes that any collection with @Singular on it is an english plural and will attempt to automatically + singularize it. If this is possible, the add-one method will use this name. For example, if your collection is called statuses, then the add-one method will automatically + be called status. If lombok cannot singularize your identifier, or it is ambiguous, lombok will generate an error and force you to explicitly specify the singular name. + To do this, just pass the singular name as string, like so: @Singular("axis") List<Line> axes;. +

+ When using the java.util interfaces, lombok always uses ArrayList to store items added to the builder, because this is more efficient than adding them to a map or + set immediately, as lombok needs to compact and potentially duplicate the result. +

+ The snippet below does not show what lombok generates for a @Singular field/parameter because it is rather complicated. + You can view a snippet here. +

+
+
+
+

With Lombok

+
@HTML_PRE@
+
+
+
+

Vanilla Java

+
@HTML_POST@
+
+
+
+
+

Supported configuration keys:

+
+
lombok.builder.flagUsage = [warning | error] (default: not set)
+
Lombok will flag any usage of @Builder as a warning or error if configured.
+
lombok.singular.useGuava = [true | false] (default: false)
+
If true, lombok will use guava's ImmutableX builders and types to implement java.util collection interfaces, instead of creating + implementations based on Collections.unmodifiableX. You must ensure that guava is actually available on the classpath and buildpath if you use this setting. + Guava is used automatically if your field/parameter has one of the guava ImmutableX types. +
lombok.singular.auto = [true | false] (default: true)
+
If true (which is the default), lombok automatically tries to singularize your identifier name by assuming that it is a common english plural. + If false, you must always explicitly specify the singular name, and lombok will generate an error if you don't (useful if you write your code in a language other than english). +
+
+
+

Small print

+

+ @Singular support for java.util.NavigableMap/Set only works if you are compiling with JDK1.8 or higher. +

+ You cannot manually provide some or all parts of a @Singular node; the code lombok generates is too complex for this. If you want to + manually control (part of) the builder nodes associated with some field or parameter, don't use @Singular and add everything you need manually. +

+ The sorted collections (java.util: SortedSet, NavigableSet, SortedMap, NavigableMap and guava: ImmutableSortedSet, ImmutableSortedMap) require that the type argument of the collection has natural order (implements java.util.Comparable). There is no way to pass an explicit Comparator to use in the builder. +

+
+
+ +
+
+
+ + + -- cgit