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 +++++++++++++++++++++++++++ website/features/Singular-snippet.html | 43 +++++++ website/features/SneakyThrows.html | 2 +- website/features/Value.html | 3 +- website/features/experimental/Accessors.html | 2 +- website/features/experimental/Builder.html | 113 +----------------- website/features/experimental/index.html | 4 +- website/features/features.css | 2 +- website/features/index.html | 2 + 9 files changed, 228 insertions(+), 115 deletions(-) create mode 100644 website/features/Builder.html create mode 100644 website/features/Singular-snippet.html (limited to 'website/features') 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. +

+
+
+ +
+
+
+ + + diff --git a/website/features/Singular-snippet.html b/website/features/Singular-snippet.html new file mode 100644 index 00000000..23fcd764 --- /dev/null +++ b/website/features/Singular-snippet.html @@ -0,0 +1,43 @@ + + + + + + + + @Builder's @Singular (snippet) +
+
+
+ +

@Singular snippet

+
+
+

With Lombok

+
@HTML_PRE@
+
+
+
+

Vanilla Java

+
@HTML_POST@
+
+
+
+ +
+
+
+ + + diff --git a/website/features/SneakyThrows.html b/website/features/SneakyThrows.html index e1cd6685..1d8d3f3d 100644 --- a/website/features/SneakyThrows.html +++ b/website/features/SneakyThrows.html @@ -77,7 +77,7 @@
diff --git a/website/features/Value.html b/website/features/Value.html index 0e221b63..2e46ccf7 100644 --- a/website/features/Value.html +++ b/website/features/Value.html @@ -20,6 +20,7 @@ @Value no longer implies @Wither since lombok v0.11.8.

@Value promoted to the main lombok package since lombok v0.12.0. +

Overview

@@ -67,7 +68,7 @@
diff --git a/website/features/experimental/Accessors.html b/website/features/experimental/Accessors.html index 20590a07..65939734 100644 --- a/website/features/experimental/Accessors.html +++ b/website/features/experimental/Accessors.html @@ -97,7 +97,7 @@
diff --git a/website/features/experimental/Builder.html b/website/features/experimental/Builder.html index a8e21b9a..b335b1bc 100644 --- a/website/features/experimental/Builder.html +++ b/website/features/experimental/Builder.html @@ -12,117 +12,12 @@
Project Lombok

@Builder

... and Bob's your uncle: No-hassle fancy-pants APIs for object creation!
-
-

Since

-

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

-
-
-

Experimental

-

- Experimental because: -

- Current status: sure thing - This feature will move to the core package soon. -
-
-

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").worksAt("Mythbusters").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:

- 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. -

- 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:

- Example usage where all options are changed from their defaults:
- @Builder(builderClassName = "HelloWorldBuilder", buildMethodName = "execute", builderMethodName = "helloWorld", fluent = false, chain = false)
-

-
-
-
-

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.
-
-
-
-

Small print

-

- Another strategy for fluent APIs is that the programmer using your library statically imports your 'builder' method. In this case, you might want to name your builder - method equal to your type's name. So, the builder method for a class called Person would become person(). This is nicer if the builder method - is statically imported. -

- If the return type of your target static method is a type parameter (such as T), lombok will enforce an explicit builder class name. -

- You don't HAVE to use @Builder to build anything; you can for example put it on a static method that has lots of parameter to improve the API of it. - In this case, we suggest you use buildMethodName = to rename the build method to execute() instead. -

- The builder class will NOT get an auto-generated implementation of hashCode or equals methods! These would suggest that it is sensible to use - instances of a builder as keys in a set or map. However, that's not a sensible thing to do. Hence, no hashCode or equals. -

- Generics are sorted out for you. -

- If an explicit constructor is present, but @Builder is placed on the class, then the builder will be generated as if an explicit constructor is present with the - same arguments list as what @AllArgsConstructor would produce. If this constructor does not exist, a compile time error will result. Usually you should just either let - lombok make this constructor (delete your constructor from the source), or, move the @Builder annotation to the constructor. -

-
+
+ @Builder has been promoted to the core package in lombok release v1.16.0.
+ The documentation has been moved here: @lombok.Builder.
diff --git a/website/features/experimental/index.html b/website/features/experimental/index.html index f37712e0..0b9419bc 100644 --- a/website/features/experimental/index.html +++ b/website/features/experimental/index.html @@ -22,8 +22,6 @@ Features that receive positive community feedback and which seem to produce clean, flexible code will eventually become accepted as a core feature and move out of the experimental package.
-
@Builder
-
... and Bob's your uncle: No-hassle fancy-pants APIs for object creation!
@Accessors
A more fluent API for getters and setters.
@ExtensionMethod
@@ -50,6 +48,8 @@
@Value: Promoted
@Value has proven its value and has been moved to the main package. +
@Builder: Promoted
+
@Builder is a solid base to build APIs on, and has been moved to the main package.