aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReinier Zwitserloot <reinier@zwitserloot.com>2015-01-26 08:46:41 +0100
committerReinier Zwitserloot <reinier@zwitserloot.com>2015-01-26 08:46:41 +0100
commit63aefa41e432a050496e9f96c6ce570dde276e18 (patch)
tree4d5fb71e5d9c2a3dd865ede63c6b5ef70f0d1d0a
parent7bb2ed02c3891d240840110abb0a79949947cc16 (diff)
downloadlombok-63aefa41e432a050496e9f96c6ce570dde276e18.tar.gz
lombok-63aefa41e432a050496e9f96c6ce570dde276e18.tar.bz2
lombok-63aefa41e432a050496e9f96c6ce570dde276e18.zip
documentation for @Singular.
-rw-r--r--buildScripts/website.ant.xml7
-rw-r--r--doc/changelog.markdown6
-rw-r--r--src/core/lombok/ConfigurationKeys.java8
-rw-r--r--src/core/lombok/eclipse/handlers/HandleBuilder.java2
-rw-r--r--src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSingularizer.java2
-rw-r--r--src/core/lombok/javac/handlers/HandleBuilder.java2
-rw-r--r--src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java2
-rw-r--r--usage_examples/BuilderExample_post.jpage62
-rw-r--r--usage_examples/BuilderExample_pre.jpage10
-rw-r--r--usage_examples/Singular-snippetExample_post.jpage160
-rw-r--r--usage_examples/Singular-snippetExample_pre.jpage14
-rw-r--r--usage_examples/experimental/BuilderExample_post.jpage40
-rw-r--r--usage_examples/experimental/BuilderExample_pre.jpage7
-rw-r--r--website/features/Builder.html172
-rw-r--r--website/features/Singular-snippet.html43
-rw-r--r--website/features/SneakyThrows.html2
-rw-r--r--website/features/Value.html3
-rw-r--r--website/features/experimental/Accessors.html2
-rw-r--r--website/features/experimental/Builder.html113
-rw-r--r--website/features/experimental/index.html4
-rw-r--r--website/features/features.css2
-rw-r--r--website/features/index.html2
22 files changed, 489 insertions, 176 deletions
diff --git a/buildScripts/website.ant.xml b/buildScripts/website.ant.xml
index 6f54c0fd..b7a86cf3 100644
--- a/buildScripts/website.ant.xml
+++ b/buildScripts/website.ant.xml
@@ -149,10 +149,13 @@ such as converting the changelog into HTML, and creating javadoc.
<param name="transformationName" value="NonNull" />
</antcall>
<antcall target="-integrateSnippet">
- <param name="transformationName" value="experimental/Delegate" />
+ <param name="transformationName" value="Builder" />
+ </antcall>
+ <antcall target="-integrateSnippet">
+ <param name="transformationName" value="Singular-snippet" />
</antcall>
<antcall target="-integrateSnippet">
- <param name="transformationName" value="experimental/Builder" />
+ <param name="transformationName" value="experimental/Delegate" />
</antcall>
<antcall target="-integrateSnippet">
<param name="transformationName" value="experimental/Accessors" />
diff --git a/doc/changelog.markdown b/doc/changelog.markdown
index 1f0425aa..d50089af 100644
--- a/doc/changelog.markdown
+++ b/doc/changelog.markdown
@@ -1,10 +1,12 @@
Lombok Changelog
----------------
-### v1.14.9.shadow "<del>Edgy</del> Shadowy Guinea Pig"
+### v1.14.9 "Edgy, Shadowy Guinea Pig"
* BUGFIX: `@ExtensionMethod` was broken in Eclipse using java 8. [Issue #742](https://code.google.com/p/projectlombok/issues/detail?id=742), [Issue #747](https://code.google.com/p/projectlombok/issues/detail?id=747)
-* Added a launcher to the lombok boot process which removes the need for `-Xbootclasspath` to be in your `eclipse.ini` file, and removes all non-public API and third party dependencies (such as ASM) from the lombok jar, thus removing them from your IDE's auto complete offerings in any project that uses lombok. For those debugging lombok, the launcher enables hot code replace which makes debugging a lot easier, as previously one was required to shut down the IDE, rebuild the jar, and relaunch. Add `-Dshadow.override.lombok=/path/to/lombok/bin` to the launch target for hot code replace.
* BUGFIX: delombok: Using exotic characters in your source files would overzealously backslash-u escape them. Now, all characters are printed unescaped, assuming your chosen encoding can support them. Otherwise, they are escaped. [Issue #759](https://code.google.com/p/projectlombok/issues/detail?id=759)
+* PROMOTION: `@Builder` has graduated from experimental to the main package with a few changes (additional of `@Singular`, removal of the `fluent` and `chain` options). The old one still exists and has been deprecated.
+* FEATURE: `@Builder` now supports adding the `@Singular` annotation to any field/parameter that represents a collection, which results in a method in the generated builder that takes in one element of that collection and adds it. Lombok takes care of generating the appropriate code to produce a compacted immutable version of the appropriate type. In this version, java.util collections and guava's ImmutableCollections are supported. See the [feature documentation](http://projectlombok.org/features/BuilderSingular.html) for more information.
+* FEATURE: Added a launcher to the lombok boot process which removes the need for `-Xbootclasspath` to be in your `eclipse.ini` file, and removes all non-public API and third party dependencies (such as ASM) from the lombok jar, thus removing them from your IDE's auto complete offerings in any project that uses lombok. For those debugging lombok, the launcher enables hot code replace which makes debugging a lot easier, as previously one was required to shut down the IDE, rebuild the jar, and relaunch. Add `-Dshadow.override.lombok=/path/to/lombok/bin` to the launch target for hot code replace.
* Builder __TODO TODO TODO TODO DO NOT SHIP YET__:
diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java
index 9b7c6c0a..8d8fb03b 100644
--- a/src/core/lombok/ConfigurationKeys.java
+++ b/src/core/lombok/ConfigurationKeys.java
@@ -176,15 +176,15 @@ public class ConfigurationKeys {
*/
public static final ConfigurationKey<FlagUsageType> BUILDER_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.builder.flagUsage", "Emit a warning or error if @Builder is used.") {};
+ // ----- Singular -----
+
/**
- * lombok configuration: {@code lombok.builder.useGuava} = {@code true} | {@code false}.
+ * lombok configuration: {@code lombok.singular.useGuava} = {@code true} | {@code false}.
*
* If explicitly set to {@code true}, guava's {@code ImmutableList} etc are used to implement the immutable collection datatypes generated by @Singular @Builder for fields/parameters of type {@code java.util.List} and such.
* By default, unmodifiable-wrapped versions of {@code java.util} types are used.
*/
- public static final ConfigurationKey<Boolean> BUILDER_USE_GUAVA = new ConfigurationKey<Boolean>("lombok.builder.useGuava", "Generate backing immutable implementations for @Singular on java.util.* types by using guava's ImmutableList, etc. Normally java.util's mutable types are used and wrapped to make them immutable.") {};
-
- // ----- Singular -----
+ public static final ConfigurationKey<Boolean> SINGULAR_USE_GUAVA = new ConfigurationKey<Boolean>("lombok.singular.useGuava", "Generate backing immutable implementations for @Singular on java.util.* types by using guava's ImmutableList, etc. Normally java.util's mutable types are used and wrapped to make them immutable.") {};
/**
* lombok configuration: {@code lombok.singular.auto} = {@code true} | {@code false}.
diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java
index 498808bc..45f4342e 100644
--- a/src/core/lombok/eclipse/handlers/HandleBuilder.java
+++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java
@@ -105,8 +105,6 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
}
@Override public void handle(AnnotationValues<Builder> annotation, Annotation ast, EclipseNode annotationNode) {
- handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.BUILDER_FLAG_USAGE, "@Builder");
-
long p = (long) ast.sourceStart << 32 | ast.sourceEnd;
Builder builderInstance = annotation.getInstance();
diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSingularizer.java
index e4c399ed..6661f4af 100644
--- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSingularizer.java
+++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSingularizer.java
@@ -87,7 +87,7 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
protected final EclipseSingularizer guavaMapSingularizer = new EclipseGuavaMapSingularizer();
protected boolean useGuavaInstead(EclipseNode node) {
- return Boolean.TRUE.equals(node.getAst().readConfiguration(ConfigurationKeys.BUILDER_USE_GUAVA));
+ return Boolean.TRUE.equals(node.getAst().readConfiguration(ConfigurationKeys.SINGULAR_USE_GUAVA));
}
protected List<Statement> createJavaUtilSetMapInitialCapacitySwitchStatements(SingularData data, EclipseNode builderType, boolean mapMode, String emptyCollectionMethod, String singletonCollectionMethod, String targetType) {
diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java
index e251e0ce..4f7f79d9 100644
--- a/src/core/lombok/javac/handlers/HandleBuilder.java
+++ b/src/core/lombok/javac/handlers/HandleBuilder.java
@@ -86,8 +86,6 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
}
@Override public void handle(AnnotationValues<Builder> annotation, JCAnnotation ast, JavacNode annotationNode) {
- handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.BUILDER_FLAG_USAGE, "@Builder");
-
Builder builderInstance = annotation.getInstance();
// These exist just to support the 'old' lombok.experimental.Builder, which had these properties. lombok.Builder no longer has them.
diff --git a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java
index 6aeadfea..c75dfbdd 100644
--- a/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java
+++ b/src/core/lombok/javac/handlers/singulars/JavacJavaUtilSingularizer.java
@@ -43,7 +43,7 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer {
protected final JavacSingularizer guavaMapSingularizer = new JavacGuavaMapSingularizer();
protected boolean useGuavaInstead(JavacNode node) {
- return Boolean.TRUE.equals(node.getAst().readConfiguration(ConfigurationKeys.BUILDER_USE_GUAVA));
+ return Boolean.TRUE.equals(node.getAst().readConfiguration(ConfigurationKeys.SINGULAR_USE_GUAVA));
}
protected List<JCStatement> createJavaUtilSetMapInitialCapacitySwitchStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, boolean mapMode, String emptyCollectionMethod, String singletonCollectionMethod, String targetType, JCTree source) {
diff --git a/usage_examples/BuilderExample_post.jpage b/usage_examples/BuilderExample_post.jpage
new file mode 100644
index 00000000..0446a0dc
--- /dev/null
+++ b/usage_examples/BuilderExample_post.jpage
@@ -0,0 +1,62 @@
+import java.util.Set;
+
+public class BuilderExample {
+ private String name;
+ private int age;
+ private Set<String> occupations;
+
+ BuilderExample(String name, int age, Set<String> occupations) {
+ this.name = name;
+ this.age = age;
+ this.occupations = occupations;
+ }
+
+ public static BuilderExampleBuilder builder() {
+ return new BuilderExampleBuilder();
+ }
+
+ public static class BuilderExampleBuilder {
+ private String name;
+ private int age;
+ private java.util.ArrayList<String> occupations;
+
+ BuilderExampleBuilder() {
+ }
+
+ public BuilderExampleBuilder name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public BuilderExampleBuilder age(int age) {
+ this.age = age;
+ return this;
+ }
+
+ public BuilderExampleBuilder occupation(String occupation) {
+ if (this.occupations == null) {
+ this.occupations = new java.util.ArrayList<String>();
+ }
+ this.occupations.add(occupation);
+ }
+
+ public BuilderExampleBuilder occupations(Collection<? extends String> occupations) {
+ if (this.occupations == null) {
+ this.occupations = new java.util.ArrayList<String>();
+ }
+ this.occupations.addAll(occupations);
+ }
+
+ public BuilderExample build() {
+ // complicated switch statement to produce a compact properly sized immutable set omitted.
+ // go to http://projectlombok.org/features/Singular-snippet.html to see it.
+ Set<String> occupations = ...;
+ return new BuilderExample(name, age, occupations);
+ }
+
+ @java.lang.Override
+ public String toString() {
+ return "BuilderExample.BuilderExampleBuilder(name = " + this.name + ", age = " + this.age + ", occupations = " + this.occupations + ")";
+ }
+ }
+} \ No newline at end of file
diff --git a/usage_examples/BuilderExample_pre.jpage b/usage_examples/BuilderExample_pre.jpage
new file mode 100644
index 00000000..374799ad
--- /dev/null
+++ b/usage_examples/BuilderExample_pre.jpage
@@ -0,0 +1,10 @@
+import lombok.Builder;
+import lombok.Singular;
+import java.util.Set;
+
+@Builder
+public class BuilderExample {
+ private String name;
+ private int age;
+ @Singular Set<String> occupations;
+}
diff --git a/usage_examples/Singular-snippetExample_post.jpage b/usage_examples/Singular-snippetExample_post.jpage
new file mode 100644
index 00000000..689d97e8
--- /dev/null
+++ b/usage_examples/Singular-snippetExample_post.jpage
@@ -0,0 +1,160 @@
+import java.util.Collection;
+import java.util.Set;
+import java.util.SortedMap;
+import com.google.common.collect.ImmutableList;
+
+public class SingularExample<T extends Number> {
+ private Set<String> occupations;
+ private ImmutableList<String> axes;
+ private SortedMap<Integer, T> elves;
+ private Collection<?> minutiae;
+
+ SingularExample(final Set<String> occupations, final ImmutableList<String> axes, final SortedMap<Integer, T> elves, final Collection<?> minutiae) {
+ this.occupations = occupations;
+ this.axes = axes;
+ this.elves = elves;
+ this.minutiae = minutiae;
+ }
+
+ public static class SingularExampleBuilder<T extends Number> {
+ private java.util.ArrayList<String> occupations;
+ private com.google.common.collect.ImmutableList.Builder<String> axes;
+ private java.util.ArrayList<Integer> elves$key;
+ private java.util.ArrayList<T> elves$value;
+ private java.util.ArrayList<java.lang.Object> minutiae;
+
+ SingularExampleBuilder() {
+ }
+
+ public SingularExampleBuilder<T> occupation(final String occupation) {
+ if (this.occupations == null) {
+ this.occupations = new java.util.ArrayList<String>();
+ }
+
+ this.occupations.add(occupation);
+ return this;
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public SingularExampleBuilder<T> occupations(final java.util.Collection<? extends String> occupations) {
+ if (this.occupations == null) {
+ this.occupations = new java.util.ArrayList<String>();
+ }
+
+ this.occupations.addAll(occupations);
+ return this;
+ }
+
+ public SingularExampleBuilder<T> axis(final String axis) {
+ if (this.axes == null) {
+ this.axes = com.google.common.collect.ImmutableList.builder();
+ }
+
+ this.axes.add(axis);
+ return this;
+ }
+
+ public SingularExampleBuilder<T> axes(final java.lang.Iterable<? extends String> axes) {
+ if (this.axes == null) {
+ this.axes = com.google.common.collect.ImmutableList.builder();
+ }
+
+ this.axes.addAll(axes);
+ return this;
+ }
+
+ public SingularExampleBuilder<T> elf(final Integer elfKey, final T elfValue) {
+ if (this.elves$key == null) {
+ this.elves$key = new java.util.ArrayList<Integer>();
+ this.elves$value = new java.util.ArrayList<T>();
+ }
+
+ this.elves$key.add(elfKey);
+ this.elves$value.add(elfValue);
+ return this;
+ }
+
+ public SingularExampleBuilder<T> elves(final java.util.Map<? extends Integer, ? extends T> elves) {
+ if (this.elves$key == null) {
+ this.elves$key = new java.util.ArrayList<Integer>();
+ this.elves$value = new java.util.ArrayList<T>();
+ }
+
+ for (final java.util.Map.Entry<? extends Integer, ? extends T> $lombokEntry : elves.entrySet()) {
+ this.elves$key.add($lombokEntry.getKey());
+ this.elves$value.add($lombokEntry.getValue());
+ }
+ return this;
+ }
+
+ public SingularExampleBuilder<T> minutia(final java.lang.Object minutia) {
+ if (this.minutiae == null) {
+ this.minutiae = new java.util.ArrayList<java.lang.Object>();
+ }
+
+ this.minutiae.add(minutia);
+ return this;
+ }
+
+ public SingularExampleBuilder<T> minutiae(final java.util.Collection<?> minutiae) {
+ if (this.minutiae == null) {
+ this.minutiae = new java.util.ArrayList<java.lang.Object>();
+ }
+
+ this.minutiae.addAll(minutiae);
+ return this;
+ }
+
+ public SingularExample<T> build() {
+ java.util.Set<String> occupations;
+ switch (this.occupations == null ? 0 : this.occupations.size()) {
+ case 0:
+ occupations = java.util.Collections.emptySet();
+ break;
+
+ case 1:
+ occupations = java.util.Collections.singleton(this.occupations.get(0));
+ break;
+
+ default:
+ occupations = new java.util.LinkedHashSet<String>(this.occupations.size() < 1073741824 ? 1 + this.occupations.size() + (this.occupations.size() - 3) / 3 : java.lang.Integer.MAX_VALUE);
+ occupations.addAll(this.occupations);
+ occupations = java.util.Collections.unmodifiableSet(occupations);
+
+ }
+
+ com.google.common.collect.ImmutableList<String> axes = this.axes == null ? com.google.common.collect.ImmutableList.<String>of() : this.axes.build();
+
+ java.util.SortedMap<Integer, T> elves = new java.util.TreeMap<Integer, T>();
+ if (this.elves$key != null) for (int $i = 0; $i < (this.elves$key == null ? 0 : this.elves$key.size()); $i++) elves.put(this.elves$key.get($i), this.elves$value.get($i));
+ elves = java.util.Collections.unmodifiableSortedMap(elves);
+
+ java.util.Collection<java.lang.Object> minutiae;
+ switch (this.minutiae == null ? 0 : this.minutiae.size()) {
+ case 0:
+ minutiae = java.util.Collections.emptyList();
+ break;
+
+ case 1:
+ minutiae = java.util.Collections.singletonList(this.minutiae.get(0));
+ break;
+
+ default:
+ minutiae = java.util.Collections.unmodifiableList(new java.util.ArrayList<java.lang.Object>(this.minutiae));
+
+ }
+
+ return new SingularExample<T>(occupations, axes, elves, minutiae);
+ }
+
+ @java.lang.Override
+ public java.lang.String toString() {
+ return "SingularExample.SingularExampleBuilder(occupations=" + this.occupations + ", axes=" + this.axes + ", elves$key=" + this.elves$key + ", elves$value=" + this.elves$value + ", minutiae=" + this.minutiae + ")";
+ }
+ }
+
+ @java.lang.SuppressWarnings("all")
+ public static <T extends Number> SingularExampleBuilder<T> builder() {
+ return new SingularExampleBuilder<T>();
+ }
+}
diff --git a/usage_examples/Singular-snippetExample_pre.jpage b/usage_examples/Singular-snippetExample_pre.jpage
new file mode 100644
index 00000000..65f6bbc8
--- /dev/null
+++ b/usage_examples/Singular-snippetExample_pre.jpage
@@ -0,0 +1,14 @@
+import lombok.Builder;
+import lombok.Singular;
+import java.util.Collection;
+import java.util.Set;
+import java.util.SortedMap;
+import com.google.common.collect.ImmutableList;
+
+@Builder
+public class SingularExample<T extends Number> {
+ private @Singular Set<String> occupations;
+ private @Singular("axis") ImmutableList<String> axes;
+ private @Singular SortedMap<Integer, T> elves;
+ private @Singular Collection<?> minutiae;
+}
diff --git a/usage_examples/experimental/BuilderExample_post.jpage b/usage_examples/experimental/BuilderExample_post.jpage
deleted file mode 100644
index 624b236b..00000000
--- a/usage_examples/experimental/BuilderExample_post.jpage
+++ /dev/null
@@ -1,40 +0,0 @@
-public class BuilderExample {
- private String name;
- private int age;
-
- BuilderExample(String name, int age) {
- this.name = name;
- this.age = age;
- }
-
- public static BuilderExampleBuilder builder() {
- return new BuilderExampleBuilder();
- }
-
- public static class BuilderExampleBuilder {
- private String name;
- private int age;
-
- BuilderExampleBuilder() {
- }
-
- public BuilderExampleBuilder name(String name) {
- this.name = name;
- return this;
- }
-
- public BuilderExampleBuilder age(int age) {
- this.age = age;
- return this;
- }
-
- public BuilderExample build() {
- return new BuilderExample(name, age);
- }
-
- @java.lang.Override
- public String toString() {
- return "BuilderExample.BuilderExampleBuilder(name = " + this.name + ", age = " + this.age + ")";
- }
- }
-} \ No newline at end of file
diff --git a/usage_examples/experimental/BuilderExample_pre.jpage b/usage_examples/experimental/BuilderExample_pre.jpage
deleted file mode 100644
index 9c754352..00000000
--- a/usage_examples/experimental/BuilderExample_pre.jpage
+++ /dev/null
@@ -1,7 +0,0 @@
-import lombok.experimental.Builder;
-
-@Builder
-public class BuilderExample {
- private String name;
- private int age;
-}
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 @@
+<!DOCTYPE html>
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <link rel="stylesheet" type="text/css" href="../logi/reset.css" />
+ <link rel="stylesheet" type="text/css" href="features.css" />
+ <link rel="shortcut icon" href="../favicon.ico" type="image/x-icon" />
+ <meta name="description" content="Spice up your java" />
+ <title>@Builder</title>
+</head><body><div id="pepper">
+ <div class="minimumHeight"></div>
+ <div class="meat">
+ <div class="header"><a href="../index.html">Project Lombok</a></div>
+ <h1>@Builder</h1>
+ <div class="byline">... and Bob's your uncle: No-hassle fancy-pants APIs for object creation!</div>
+ <div class="since">
+ <h3>Since</h3>
+ <p>
+ <code>@Builder</code> was introduced as experimental feature in lombok v0.12.0.
+ </p><p>
+ <code>@Builder</code> gained <code>@Singular</code> support and was promoted to the main <code>lombok</code> package since lombok v1.16.0.
+ </p>
+ </div>
+ <div class="overview">
+ <h3>Overview</h3>
+ <p>
+ The <code>@Builder</code> annotation produces complex builder APIs for your classes.
+ </p><p>
+ <code>@Builder</code> lets you automatically produce the code required to have your class be instantiable with code such as:<br />
+ <code>Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build();</code>
+ </p><p>
+ <code>@Builder</code> 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, <code>@Builder</code> is most easily explained with the "static method" use-case.
+ </p><p>
+ A static method annotated with <code>@Builder</code> (from now on called the <em>target</em>) causes the following 7 things to be generated:<ul>
+ <li>An inner static class named <code><em>Foo</em>Builder</code>, with the same type arguments as the static method (called the <em>builder</em>).</li>
+ <li>In the <em>builder</em>: One private non-static non-final field for each parameter of the <em>target</em>.</li>
+ <li>In the <em>builder</em>: A package private no-args empty constructor.</li>
+ <li>In the <em>builder</em>: A 'setter'-like method for each parameter of the <em>target</em>: 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.</li>
+ <li>In the <em>builder</em>: A <code>build()</code> method which calls the static method, passing in each field. It returns the same type that the
+ <em>target</em> returns.</li>
+ <li>In the <em>builder</em>: A sensible <code>toString()</code> implementation.</li>
+ <li>In the class containing the <em>target</em>: A <code>builder()</code> method, which creates a new instance of the <em>builder</em>.</li>
+ </ul>
+ Each listed generated element will be silently skipped if that element already exists (disregarding parameter counts and looking only at names). This
+ includes the <em>builder</em> 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 <code>@EqualsAndHashCode</code> on the builder class.
+ </p><p>
+ <code>@Builder</code> 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: <code>Person.builder().job("Mythbusters").job("Unchained Reaction").build();</code> would result in the <code>List&lt;String&gt; jobs</code>
+ field to have 2 strings in it. To get this behaviour, the field/parameter needs to be annotated with <code>@Singular</code>. The feature has <a href="#singular">its own documentation</a>.
+ </p><p>
+ Now that the "static method" mode is clear, putting a <code>@Builder</code> 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.
+ </p><p>
+ Finally, applying <code>@Builder</code> to a class is as if you added <code>@AllArgsConstructor(access = AccessLevel.PACKAGE)</code> to the class and applied the
+ <code>@Builder</code> 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 <code>@Builder</code> annotation on the constructor instead of on the class.
+ </p><p>
+ The name of the builder class is <code><em>Foobar</em>Builder</code>, where <em>Foobar</em> is the simplified, title-cased form of the return type of the
+ <em>target</em> - that is, the name of your type for <code>@Builder</code> on constructors and types, and the name of the return type for <code>@Builder</code>
+ on static methods. For example, if <code>@Builder</code> is applied to a class named <code>com.yoyodyne.FancyList&lt;T&gt;</code>, then the builder name will be
+ <code>FancyListBuilder&lt;T&gt;</code>. If <code>@Builder</code> is applied to a static method that returns <code>void</code>, the builder will be named
+ <code>VoidBuilder</code>.
+ </p><p>
+ The configurable aspects of builder are:<ul>
+ <li>The <em>builder's class name</em> (default: return type + 'Builder')</li>
+ <li>The <em>build()</em> method's name (default: <code>"build"</code>)</li>
+ <li>The <em>builder()</em> method's name (default: <code>"builder"</code>)</li>
+ </ul>
+ Example usage where all options are changed from their defaults:<br />
+ <code>@Builder(builderClassName = "HelloWorldBuilder", buildMethodName = "execute", builderMethodName = "helloWorld")</code><br />
+ </p>
+ </div>
+ <div class="overview">
+ <h3><a name="singular">@Singular</a></h3>
+ <p>
+ By annotating one of the parameters (if annotating a static method or constructor with <code>@Builder</code>) or fields (if annotating a class with <code>@Builder</code>) with the
+ <code>@Singular</code> 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:
+ <ul>
+ <li>When invoking <code>build()</code>, the produced collection will be immutable.</li>
+ <li>Repeatedly invoking <code>build()</code> works fine and does not corrupt any of the collections already generated.</li>
+ <li>Calling one of the 'adder' methods after invoking <code>build()</code> does not modify any already generated objects, and, if <code>build()</code> is later called again,
+ <li>The produced collection will be compacted to the smallest feasible format while remaining efficient.</li>
+ </ul>
+ </p><p>
+ <code>@Singular</code> can only be applied to collection types for which lombok has a recipe to produce the singular methods. Currently, the supported types are:
+ <ul>
+ <li><a href="http://docs.oracle.com/javase/8/docs/api/java/util/package-summary.html"><code>java.util</code></a>:<ul>
+ <li><code>Collection</code> and <code>List</code> (backed by a compacted unmodifiable <code>ArrayList</code> in the general case).</li>
+ <li><code>Set</code>, <code>SortedSet</code>, and <code>NavigableSet</code> (backed by a smartly sized unmodifiable <code>HashSet</code> or <code>TreeSet</code> in the general case).</li>
+ <li><code>Map</code>, <code>SortedMap</code>, and <code>NavigableMap</code> (backed by a smartly sized unmodifiable <code>HashMap</code> or <code>TreeMap</code> in the general case).</li>
+ </ul></li>
+ <li><a href="https://github.com/google/guava">Guava</a>'s <code>com.google.common.collect</code>:<ul>
+ <li><code>ImmutableCollection</code> and <code>ImmutableList</code> (backed by the builder feature of <code>ImmutableList</code>).</li>
+ <li><code>ImmutableSet</code> and <code>ImmutableSortedSet</code> (backed by the builder feature of those types).</li>
+ <li><code>ImmutableMap</code>, <code>ImmutableBiMap</code>, and ImmutableSortedMap</code> (backed by the builder feature of those types).</li>
+ </ul></li>
+ </ul>
+ </p><p>
+ If your identifiers are written in common english, lombok assumes that any collection with <code>@Singular</code> 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 <code>statuses</code>, then the add-one method will automatically
+ be called <code>status</code>. 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: <code>@Singular("axis") List&lt;Line&gt; axes;</code>.
+ </p><p>
+ When using the <code>java.util</code> interfaces, lombok always uses <code>ArrayList</code> 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.
+ </p><p>
+ The snippet below does not show what lombok generates for a <code>@Singular</code> field/parameter because it is rather complicated.
+ You can view a snippet <a href="Singular-snippet.html">here</a>.
+ </p>
+ </div>
+ <div class="snippets">
+ <div class="pre">
+ <h3>With Lombok</h3>
+ <div class="snippet">@HTML_PRE@</div>
+ </div>
+ <div class="sep"></div>
+ <div class="post">
+ <h3>Vanilla Java</h3>
+ <div class="snippet">@HTML_POST@</div>
+ </div>
+ </div>
+ <div style="clear: left;"></div>
+ <div class="overview confKeys">
+ <h3>Supported configuration keys:</h3>
+ <dl>
+ <dt><code>lombok.builder.flagUsage</code> = [<code>warning</code> | <code>error</code>] (default: not set)</dt>
+ <dd>Lombok will flag any usage of <code>@Builder</code> as a warning or error if configured.</dd>
+ <dt><code>lombok.singular.useGuava</code> = [<code>true</code> | <code>false</code>] (default: false)</dt>
+ <dd>If <code>true</code>, lombok will use guava's <code>ImmutableX</code> builders and types to implement <code>java.util</code> collection interfaces, instead of creating
+ implementations based on <code>Collections.unmodifiableX</code>. 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 <code>ImmutableX</code> types.
+ <dt><code>lombok.singular.auto</code> = [<code>true</code> | <code>false</code>] (default: true)</dt>
+ <dd>If <code>true</code> (which is the default), lombok automatically tries to singularize your identifier name by assuming that it is a common english plural.
+ If <code>false</code>, 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).
+ </dl>
+ </div>
+ <div class="overview">
+ <h3>Small print</h3><div class="smallprint">
+ <p>
+ @Singular support for <code>java.util.NavigableMap/Set</code> only works if you are compiling with JDK1.8 or higher.
+ </p><p>
+ You cannot manually provide some or all parts of a <code>@Singular</code> 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.
+ </p><p>
+ The sorted collections (java.util: <code>SortedSet</code>, <code>NavigableSet</code>, <code>SortedMap</code>, <code>NavigableMap</code> and guava: <code>ImmutableSortedSet</code>, <code>ImmutableSortedMap</code>) require that the type argument of the collection has natural order (implements <code>java.util.Comparable</code>). There is no way to pass an explicit <code>Comparator</code> to use in the builder.
+ </p>
+ </div>
+ </div>
+ <div class="footer">
+ <a href="index.html">Back to features</a> | <a href="Value.html">Previous feature (@Value)</a> | <a href="SneakyThrows.html">Next feature (@SneakyThrows)</a><br />
+ <a href="../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright &copy; 2009-2014 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span>
+ </div>
+ <div style="clear: both;"></div>
+ </div>
+</div>
+<script type="text/javascript">
+ var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+ document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+</script>
+<script type="text/javascript">
+ try {
+ var pageTracker = _gat._getTracker("UA-9884254-1");
+ pageTracker._trackPageview();
+ } catch(err) {}
+</script>
+</body></html>
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 @@
+<!DOCTYPE html>
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <link rel="stylesheet" type="text/css" href="../logi/reset.css" />
+ <link rel="stylesheet" type="text/css" href="features.css" />
+ <link rel="shortcut icon" href="../favicon.ico" type="image/x-icon" />
+ <meta name="description" content="Spice up your java" />
+ <title>@Builder's @Singular (snippet)</title>
+</head><body><div id="pepper">
+ <div class="minimumHeight"></div>
+ <div class="meat">
+ <div class="header"><a href="../index.html">Project Lombok</a></div>
+ <h1>@Singular snippet</h1>
+ <div class="singleColumnSnippets">
+ <div class="pre">
+ <h3>With Lombok</h3>
+ <div class="snippet">@HTML_PRE@</div>
+ </div>
+ <div class="sep"></div>
+ <div class="post">
+ <h3>Vanilla Java</h3>
+ <div class="snippet">@HTML_POST@</div>
+ </div>
+ </div>
+ <div style="clear: left;"></div>
+ <div class="footer">
+ <a href="Builder.html">Back to @Builder</a><br />
+ <a href="../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright &copy; 2009-2014 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span>
+ </div>
+ <div style="clear: both;"></div>
+ </div>
+</div>
+<script type="text/javascript">
+ var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+ document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+</script>
+<script type="text/javascript">
+ try {
+ var pageTracker = _gat._getTracker("UA-9884254-1");
+ pageTracker._trackPageview();
+ } catch(err) {}
+</script>
+</body></html>
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 @@
</div>
</div>
<div class="footer">
- <a href="index.html">Back to features</a> | <a href="Value.html">Previous feature (@Value)</a> | <a href="Synchronized.html">Next feature (@Synchronized)</a><br />
+ <a href="index.html">Back to features</a> | <a href="Builder.html">Previous feature (@Builder)</a> | <a href="Synchronized.html">Next feature (@Synchronized)</a><br />
<a href="../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright &copy; 2009-2014 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span>
</div>
<div style="clear: both;"></div>
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 @@
<code>@Value</code> no longer implies <code>@Wither</code> since lombok v0.11.8.
</p><p>
<code>@Value</code> promoted to the main <code>lombok</code> package since lombok v0.12.0.
+ </p>
</div>
<div class="overview">
<h3>Overview</h3>
@@ -67,7 +68,7 @@
</div>
</div>
<div class="footer">
- <a href="index.html">Back to features</a> | <a href="Data.html">Previous feature (@Data)</a> | <a href="SneakyThrows.html">Next feature (@SneakyThrows)</a><br />
+ <a href="index.html">Back to features</a> | <a href="Data.html">Previous feature (@Data)</a> | <a href="Builder.html">Next feature (@Builder)</a><br />
<a href="../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright &copy; 2009-2014 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span>
</div>
<div style="clear: both;"></div>
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 @@
</div>
</div>
<div class="footer">
- <a href="index.html">Back to experimental features</a> | <a href="Builder.html">Previous feature (@Builder)</a> | <a href="ExtensionMethod.html">Next feature (@ExtensionMethod)</a><br />
+ <a href="index.html">Back to experimental features</a> | <span class="disabled">Previous feature</span> | <a href="ExtensionMethod.html">Next feature (@ExtensionMethod)</a><br />
<a href="../../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright &copy; 2009-2014 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span>
</div>
<div style="clear: both;"></div>
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 @@
<div class="header"><a href="../../index.html">Project Lombok</a></div>
<h1>@Builder</h1>
<div class="byline">... and Bob's your uncle: No-hassle fancy-pants APIs for object creation!</div>
- <div class="since">
- <h3>Since</h3>
- <p>
- @Builder was introduced as experimental feature in lombok v0.12.0.
- </p>
- </div>
- <div class="experimental">
- <h3>Experimental</h3>
- <p>
- Experimental because:
- <ul>
- <li>New feature - community feedback requested.</li>
- </ul>
- Current status: <em>sure thing</em> - This feature will move to the core package soon.
- </div>
- <div class="overview">
- <h3>Overview</h3>
- <p>
- The <code>@Builder</code> annotation produces complex builder APIs for your classes.
- </p><p>
- <code>@Builder</code> lets you automatically produce the code required to have your class be instantiable with code such as:<br />
- <code>Person.builder().name("Adam Savage").city("San Francisco").worksAt("Mythbusters").build();</code>
- </p><p>
- <code>@Builder</code> 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, <code>@Builder</code> is most easily explained with the "static method" use-case.
- </p><p>
- A static method annotated with <code>@Builder</code> (from now on called the <em>target</em>) causes the following 7 things to be generated:<ul>
- <li>An inner static class named <code><em>Foo</em>Builder</code>, with the same type arguments as the static method (called the <em>builder</em>).</li>
- <li>In the <em>builder</em>: One private non-static non-final field for each parameter of the <em>target</em>.</li>
- <li>In the <em>builder</em>: A package private no-args empty constructor.</li>
- <li>In the <em>builder</em>: A 'setter'-like method for each parameter of the <em>target</em>: 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.</li>
- <li>In the <em>builder</em>: A <code>build()</code> method which calls the static method, passing in each field. It returns the same type that the
- <em>target</em> returns.</li>
- <li>In the <em>builder</em>: A sensible <code>toString()</code> implementation.</li>
- <li>In the class containing the <em>target</em>: A <code>builder()</code> method, which creates a new instance of the <em>builder</em>.</li>
- </ul>
- Each listed generated element will be silently skipped if that element already exists (disregarding parameter counts and looking only at names). This
- includes the <em>builder</em> 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 <code>@EqualsAndHashCode</code> on the builder class.
- </p><p>
- Now that the "static method" mode is clear, putting a <code>@Builder</code> 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.
- </p><p>
- Finally, applying <code>@Builder</code> to a class is as if you added <code>@AllArgsConstructor(access = AccessLevel.PACKAGE)</code> to the class and applied the
- <code>@Builder</code> 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 <code>@Builder</code> annotation on the constructor instead of on the class.
- </p><p>
- The name of the builder class is <code><em>Foobar</em>Builder</code>, where <em>Foobar</em> is the simplified, title-cased form of the return type of the
- <em>target</em> - that is, the name of your type for <code>@Builder</code> on constructors and types, and the name of the return type for <code>@Builder</code>
- on static methods. For example, if <code>@Builder</code> is applied to a class named <code>com.yoyodyne.FancyList&lt;T&gt;</code>, then the builder name will be
- <code>FancyListBuilder&lt;T&gt;</code>. If <code>@Builder</code> is applied to a static method that returns <code>void</code>, the builder will be named
- <code>VoidBuilder</code>.
- </p><p>
- The configurable aspects of builder are:<ul>
- <li>The <em>builder's class name</em> (default: return type + 'Builder')</li>
- <li>The <em>build()</em> method's name (default: <code>"build"</code>)</li>
- <li>The <em>builder()</em> method's name (default: <code>"builder"</code>)</li>
- <li>The 'fluent' nature of the generated 'setter'-like methods. A fluent 'setter' is named just <code>fieldName()</code>, a non-fluent one is named <code>setFieldName()</code>. (default: <code>true</code>)</li>
- <li>The 'chain' nature of the generated 'setter'-like methods. A chainable 'setter' returns the builder object itself, letting you chain 'set' calls. A non-chainable setter returns <code>void</code>. (default: <code>true</code>)</li>
- </ul>
- Example usage where all options are changed from their defaults:<br />
- <code>@Builder(builderClassName = "HelloWorldBuilder", buildMethodName = "execute", builderMethodName = "helloWorld", fluent = false, chain = false)</code><br />
- </p>
- </div>
- <div class="snippets">
- <div class="pre">
- <h3>With Lombok</h3>
- <div class="snippet">@HTML_PRE@</div>
- </div>
- <div class="sep"></div>
- <div class="post">
- <h3>Vanilla Java</h3>
- <div class="snippet">@HTML_POST@</div>
- </div>
- </div>
- <div style="clear: left;"></div>
- <div class="overview confKeys">
- <h3>Supported configuration keys:</h3>
- <dl>
- <dt><code>lombok.builder.flagUsage</code> = [<code>warning</code> | <code>error</code>] (default: not set)</dt>
- <dd>Lombok will flag any usage of <code>@Builder</code> as a warning or error if configured.</dd>
- </dl>
- </div>
- <div class="overview">
- <h3>Small print</h3><div class="smallprint">
- <p>
- 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 <code>Person</code> would become <code>person()</code>. This is nicer if the builder method
- is statically imported.
- </p><p>
- If the return type of your target static method is a type parameter (such as <code>T</code>), lombok will enforce an explicit builder class name.
- </p><p>
- You don't HAVE to use <code>@Builder</code> 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 <code>buildMethodName = </code> to rename the build method to <code>execute()</code> instead.
- </p><p>
- The builder class will NOT get an auto-generated implementation of <code>hashCode</code> or <code>equals</code> 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 <code>hashCode</code> or <code>equals</code>.
- </p><p>
- Generics are sorted out for you.
- </p><p>
- If an explicit constructor is present, but <code>@Builder</code> 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 <code>@AllArgsConstructor</code> 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 <code>@Builder</code> annotation to the constructor.
- </p>
- </div>
+ <div class="moved">
+ @Builder has been promoted to the core package in lombok release v1.16.0.<br />
+ The documentation has been moved here: <a href="../Builder.html">@lombok.Builder</a>.
</div>
<div class="footer">
- <a href="index.html">Back to experimental features</a> | <span class="disabled">Previous feature</span> | <a href="Accessors.html">Next feature (@Accessors)</a><br />
+ <a href="index.html">Back to experimental features</a><br />
<a href="../../credits.html" class="creditsLink">credits</a> | <span class="copyright">Copyright &copy; 2009-2014 The Project Lombok Authors, licensed under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT license</a>.</span>
</div>
<div style="clear: both;"></div>
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.
<dl>
- <dt><a href="Builder.html"><code>@Builder</code></a></dt>
- <dd>... and Bob's your uncle: No-hassle fancy-pants APIs for object creation!</dd>
<dt><a href="Accessors.html"><code>@Accessors</code></a></dt>
<dd>A more fluent API for getters and setters.</dd>
<dt><a href="ExtensionMethod.html"><code>@ExtensionMethod</code></a></dt>
@@ -50,6 +48,8 @@
<dl>
<dt><a href="../Value.html"><code>@Value</code></a>: Promoted</dt>
<dd><code>@Value</code> has proven its value and has been moved to the main package.</li>
+ <dt><a href="../Builder.html"><code>@Builder</code></a>: Promoted</dt>
+ <dd><code>@Builder</code> is a solid base to build APIs on, and has been moved to the main package.</li>
</dl>
</div>
<div class="footer">
diff --git a/website/features/features.css b/website/features/features.css
index b3017fe8..58897ccd 100644
--- a/website/features/features.css
+++ b/website/features/features.css
@@ -92,7 +92,7 @@ dd {
white-space: nowrap;
}
-.snippets {
+.snippets, .singleColumnSnippets {
margin-top: 0px;
}
diff --git a/website/features/index.html b/website/features/index.html
index 09a148f0..f285c7a8 100644
--- a/website/features/index.html
+++ b/website/features/index.html
@@ -32,6 +32,8 @@
<code>@Getter</code> on all fields, and <code>@Setter</code> on all non-final fields, and <code>@RequiredArgsConstructor</code>!</dd>
<dt><a href="Value.html"><code>@Value</code></a></dt>
<dd>Immutable classes made very easy.</dd>
+ <dt><a href="Builder.html"><code>@Builder</code></a></dt>
+ <dd>... and Bob's your uncle: No-hassle fancy-pants APIs for object creation!</dd>
<dt><a href="SneakyThrows.html"><code>@SneakyThrows</code></a></dt>
<dd>To boldly throw checked exceptions where no one has thrown them before!</dd>
<dt><a href="Synchronized.html"><code>@Synchronized</code></a></dt>