mirror of
https://github.com/tiennm99/lombok.git
synced 2026-09-03 08:18:57 +00:00
[fixes #2046] you can now suppress the builder() method, useful if you only want toBuilder(). Also suppresses the warnings about any missing Builder.Default annotations.
This commit is contained in:
@@ -3,6 +3,7 @@ Lombok Changelog
|
||||
|
||||
### v1.18.7 "Edgy Guinea Pig"
|
||||
* BUGFIX: var/val on methods that return an intersection type would now work in Eclipse [Issue #1986](https://github.com/rzwitserloot/lombok/issues/1986)
|
||||
* FEATURE: You can now suppress generation of the `builder` method when using `@Builder`; usually because you're only interested in the `toBuilder` method. As a convenience we won't emit warnings about missing `@Builder.Default` annotations when you do this. [Issue #2046](https://github.com/rzwitserloot/lombok/issues/2046)
|
||||
|
||||
### v1.18.6 (February 12th, 2019)
|
||||
* FEATURE: Javadoc on fields will now also be copied to the Builders' setters. Thanks for the contribution, Emil Lundberg. [Issue #2008](https://github.com/rzwitserloot/lombok/issues/2008)
|
||||
|
||||
@@ -173,7 +173,15 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
if (buildMethodName == null) builderMethodName = "build";
|
||||
if (builderClassName == null) builderClassName = "";
|
||||
|
||||
if (!checkName("builderMethodName", builderMethodName, annotationNode)) return;
|
||||
boolean generateBuilderMethod;
|
||||
if (builderMethodName.isEmpty()) {
|
||||
generateBuilderMethod = false;
|
||||
} else if (!checkName("builderMethodName", builderMethodName, annotationNode)) {
|
||||
return;
|
||||
} else {
|
||||
generateBuilderMethod = true;
|
||||
}
|
||||
|
||||
if (!checkName("buildMethodName", buildMethodName, annotationNode)) return;
|
||||
if (!builderClassName.isEmpty()) {
|
||||
if (!checkName("builderClassName", builderClassName, annotationNode)) return;
|
||||
@@ -192,6 +200,8 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
boolean addCleaning = false;
|
||||
boolean isStatic = true;
|
||||
|
||||
List<EclipseNode> nonFinalNonDefaultedFields = null;
|
||||
|
||||
if (parent.get() instanceof TypeDeclaration) {
|
||||
tdParent = parent;
|
||||
TypeDeclaration td = (TypeDeclaration) tdParent.get();
|
||||
@@ -225,7 +235,8 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
|
||||
if (fd.initialization != null && isDefault == null) {
|
||||
if (isFinal) continue;
|
||||
fieldNode.addWarning("@Builder will ignore the initializing expression entirely. If you want the initializing expression to serve as default, add @Builder.Default. If it is not supposed to be settable during building, make the field final.");
|
||||
if (nonFinalNonDefaultedFields == null) nonFinalNonDefaultedFields = new ArrayList<EclipseNode>();
|
||||
nonFinalNonDefaultedFields.add(fieldNode);
|
||||
}
|
||||
|
||||
if (isDefault != null) {
|
||||
@@ -486,7 +497,8 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
if (cleanMethod != null) injectMethod(builderType, cleanMethod);
|
||||
}
|
||||
|
||||
if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) {
|
||||
if (generateBuilderMethod && methodExists(builderMethodName, tdParent, -1) != MemberExistsResult.NOT_EXISTS) generateBuilderMethod = false;
|
||||
if (generateBuilderMethod) {
|
||||
MethodDeclaration md = generateBuilderMethod(isStatic, builderMethodName, builderClassName, tdParent, typeParams, ast);
|
||||
if (md != null) injectMethod(tdParent, md);
|
||||
}
|
||||
@@ -508,6 +520,12 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
|
||||
if (md != null) injectMethod(tdParent, md);
|
||||
}
|
||||
|
||||
if (nonFinalNonDefaultedFields != null && generateBuilderMethod) {
|
||||
for (EclipseNode fieldNode : nonFinalNonDefaultedFields) {
|
||||
fieldNode.addWarning("@Builder will ignore the initializing expression entirely. If you want the initializing expression to serve as default, add @Builder.Default. If it is not supposed to be settable during building, make the field final.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final char[] BUILDER_TEMP_VAR = {'b', 'u', 'i', 'l', 'd', 'e', 'r'};
|
||||
|
||||
@@ -119,7 +119,15 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
if (buildMethodName == null) buildMethodName = "build";
|
||||
if (builderClassName == null) builderClassName = "";
|
||||
|
||||
if (!checkName("builderMethodName", builderMethodName, annotationNode)) return;
|
||||
boolean generateBuilderMethod;
|
||||
if (builderMethodName.isEmpty()) {
|
||||
generateBuilderMethod = false;
|
||||
} else if (!checkName("builderMethodName", builderMethodName, annotationNode)) {
|
||||
return;
|
||||
} else {
|
||||
generateBuilderMethod = true;
|
||||
}
|
||||
|
||||
if (!checkName("buildMethodName", buildMethodName, annotationNode)) return;
|
||||
if (!builderClassName.isEmpty()) {
|
||||
if (!checkName("builderClassName", builderClassName, annotationNode)) return;
|
||||
@@ -140,6 +148,8 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
boolean addCleaning = false;
|
||||
boolean isStatic = true;
|
||||
|
||||
ArrayList<JavacNode> nonFinalNonDefaultedFields = null;
|
||||
|
||||
if (parent.get() instanceof JCClassDecl) {
|
||||
tdParent = parent;
|
||||
JCClassDecl td = (JCClassDecl) tdParent.get();
|
||||
@@ -172,7 +182,8 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
|
||||
if (fd.init != null && isDefault == null) {
|
||||
if (isFinal) continue;
|
||||
fieldNode.addWarning("@Builder will ignore the initializing expression entirely. If you want the initializing expression to serve as default, add @Builder.Default. If it is not supposed to be settable during building, make the field final.");
|
||||
if (nonFinalNonDefaultedFields == null) nonFinalNonDefaultedFields = new ArrayList<JavacNode>();
|
||||
nonFinalNonDefaultedFields.add(fieldNode);
|
||||
}
|
||||
|
||||
if (isDefault != null) {
|
||||
@@ -431,7 +442,8 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
|
||||
if (addCleaning) injectMethod(builderType, generateCleanMethod(builderFields, builderType, ast));
|
||||
|
||||
if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) {
|
||||
if (generateBuilderMethod && methodExists(builderMethodName, tdParent, -1) != MemberExistsResult.NOT_EXISTS) generateBuilderMethod = false;
|
||||
if (generateBuilderMethod) {
|
||||
JCMethodDecl md = generateBuilderMethod(isStatic, builderMethodName, builderClassName, annotationNode, tdParent, typeParams);
|
||||
recursiveSetGeneratedBy(md, ast, annotationNode.getContext());
|
||||
if (md != null) injectMethod(tdParent, md);
|
||||
@@ -459,6 +471,12 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nonFinalNonDefaultedFields != null && generateBuilderMethod) {
|
||||
for (JavacNode fieldNode : nonFinalNonDefaultedFields) {
|
||||
fieldNode.addWarning("@Builder will ignore the initializing expression entirely. If you want the initializing expression to serve as default, add @Builder.Default. If it is not supposed to be settable during building, make the field final.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String unpack(JCExpression expr) {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
class BuilderWithNoBuilderMethod {
|
||||
private String a = "";
|
||||
@java.lang.SuppressWarnings("all")
|
||||
BuilderWithNoBuilderMethod(final String a) {
|
||||
this.a = a;
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static class BuilderWithNoBuilderMethodBuilder {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private String a;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
BuilderWithNoBuilderMethodBuilder() {
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public BuilderWithNoBuilderMethodBuilder a(final String a) {
|
||||
this.a = a;
|
||||
return this;
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public BuilderWithNoBuilderMethod build() {
|
||||
return new BuilderWithNoBuilderMethod(a);
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public java.lang.String toString() {
|
||||
return "BuilderWithNoBuilderMethod.BuilderWithNoBuilderMethodBuilder(a=" + this.a + ")";
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public BuilderWithNoBuilderMethodBuilder toBuilder() {
|
||||
return new BuilderWithNoBuilderMethodBuilder().a(this.a);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import lombok.Builder;
|
||||
@Builder(toBuilder = true,builderMethodName = "") class BuilderWithNoBuilderMethod {
|
||||
public static @java.lang.SuppressWarnings("all") class BuilderWithNoBuilderMethodBuilder {
|
||||
private @java.lang.SuppressWarnings("all") String a;
|
||||
@java.lang.SuppressWarnings("all") BuilderWithNoBuilderMethodBuilder() {
|
||||
super();
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderWithNoBuilderMethodBuilder a(final String a) {
|
||||
this.a = a;
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderWithNoBuilderMethod build() {
|
||||
return new BuilderWithNoBuilderMethod(a);
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
|
||||
return (("BuilderWithNoBuilderMethod.BuilderWithNoBuilderMethodBuilder(a=" + this.a) + ")");
|
||||
}
|
||||
}
|
||||
private String a = "";
|
||||
@java.lang.SuppressWarnings("all") BuilderWithNoBuilderMethod(final String a) {
|
||||
super();
|
||||
this.a = a;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") BuilderWithNoBuilderMethodBuilder toBuilder() {
|
||||
return new BuilderWithNoBuilderMethodBuilder().a(this.a);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import lombok.Builder;
|
||||
@Builder(toBuilder = true, builderMethodName = "")
|
||||
class BuilderWithNoBuilderMethod {
|
||||
private String a = "";
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
13 @Builder.Default requires @Builder on the class for it to mean anything.
|
||||
6 @Builder will ignore the initializing expression entirely. If you want the initializing expression to serve as default, add @Builder.Default. If it is not supposed to be settable during building, make the field final.
|
||||
8 @Builder.Default requires an initializing expression (' = something;').
|
||||
9 @Builder.Default and @Singular cannot be mixed.
|
||||
6 @Builder will ignore the initializing expression entirely. If you want the initializing expression to serve as default, add @Builder.Default. If it is not supposed to be settable during building, make the field final.
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
<code>@Builder</code> with <code>@Singular</code> adds a clear method since lombok v1.16.8.
|
||||
</p><p>
|
||||
<code>@Builder.Default</code> functionality was added in lombok v1.16.16.
|
||||
</p><p>
|
||||
<code>@Builder(builderMethodName = "")</code> is legal (and will suppress generation of the builder method) starting with lombok v1.18.8.
|
||||
</p>
|
||||
</@f.history>
|
||||
|
||||
@@ -183,6 +185,13 @@ public class JacksonExample {
|
||||
The initializer on a <code>@Builder.Default</code> field is removed and stored in a static method, in order to guarantee that this initializer won't be executed at all if a value is specified in the build. This does mean the initializer cannot refer to <code>this</code>, <code>super</code> or any non-static member. If lombok generates a constructor for you, it'll also initialize this field with the initializer.
|
||||
</p><p>
|
||||
Various well known annotations about nullity cause null checks to be inserted and will be copied to parameter of the builder's 'setter' method. See <a href="/features/GetterSetter">Getter/Setter</a> documentation's small print for more information.
|
||||
</p><p>
|
||||
You can suppress the generation of the <code>builder()</code> method, for example because you <em>just</em> want the <code>toBuilder()</code> functionality, by using:
|
||||
<code>@Builder(builderMethodName = "")</code>. Any warnings about missing <code>@Builder.Default</code> annotations will disappear when you do this, as such warnings
|
||||
are not relevant when only using <code>toBuilder()</code> to make builder instances.
|
||||
</p><p>
|
||||
You can use <code>@Builder</code> for copy constructors: <code>foo.toBuilder().build()</code> makes a shallow clone. Consider suppressing the generating of the
|
||||
<code>builder</code> method if you just want this functionality, by using: <code>@Builder(toBuilder = true, builderMethodName = "")</code>.
|
||||
</p><p>
|
||||
Due to a peculiar way javac processes static imports, trying to do a non-star static import of the static <code>builder()</code> method won't work. Either use a star static import: `import static TypeThatHasABuilder.*;` or don't statically import the <code>builder</code> method.
|
||||
</p>
|
||||
|
||||
Reference in New Issue
Block a user