From 63aefa41e432a050496e9f96c6ce570dde276e18 Mon Sep 17 00:00:00 2001
From: Reinier Zwitserloot
+
+
+ The
+
+
+ A static method annotated with
+
+ Now that the "static method" mode is clear, putting a
+ Finally, applying
+ The name of the builder class is
+ The configurable aspects of builder are:
+ By annotating one of the parameters (if annotating a static method or constructor with
+
+ If your identifiers are written in common english, lombok assumes that any collection with
+ When using the
+ The snippet below does not show what lombok generates for a
+ @Singular support for
+ You cannot manually provide some or all parts of a
+ The sorted collections (java.util: @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
+ @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.
+ @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 FooBuilder
, with the same type arguments as the static method (called the builder).build()
method which calls the static method, passing in each field. It returns the same type that the
+ target returns.toString()
implementation.builder()
method, which creates a new instance of the builder.@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.
+ @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.
+ @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.
+ 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
.
+
+
+ Example usage where all options are changed from their defaults:"build"
)"builder"
)
+ @Builder(builderClassName = "HelloWorldBuilder", buildMethodName = "execute", builderMethodName = "helloWorld")
+
+ @Singular
+ @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:
+
+
+ build()
, the produced collection will be immutable.build()
works fine and does not corrupt any of the collections already generated.build()
does not modify any already generated objects, and, if build()
is later called again,
+ @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).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).@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;
.
+ 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.
+ @Singular
field/parameter because it is rather complicated.
+ You can view a snippet here.
+ With Lombok
+ Vanilla Java
+ Supported configuration keys:
+
+
+ lombok.builder.flagUsage
= [warning
| error
] (default: not set)@Builder
as a warning or error if configured.lombok.singular.useGuava
= [true
| false
] (default: false)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)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
java.util.NavigableMap/Set
only works if you are compiling with JDK1.8 or higher.
+ @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.
+ 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.
+ @Singular snippet
+ With Lombok
+ Vanilla Java
+ @Value
no longer implies @Wither
since lombok v0.11.8.
@Value
promoted to the main lombok
package since lombok v0.12.0.
+
- @Builder was introduced as experimental feature in lombok v0.12.0. -
-- Experimental because: -
- 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:
FooBuilder
, with the same type arguments as the static method (called the builder).build()
method which calls the static method, passing in each field. It returns the same type that the
- target returns.toString()
implementation.builder()
method, which creates a new instance of the builder.@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:
"build"
)"builder"
)fieldName()
, a non-fluent one is named setFieldName()
. (default: true
)void
. (default: true
)@Builder(builderClassName = "HelloWorldBuilder", buildMethodName = "execute", builderMethodName = "helloWorld", fluent = false, chain = false)
lombok.builder.flagUsage
= [warning
| error
] (default: not set)@Builder
as a warning or error if configured.
- 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
@Accessors
@ExtensionMethod