Skip to content

Commit

Permalink
[#2046] Extend suppress builder feature to @SuperBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
rzwitserloot committed Mar 26, 2019
1 parent 5d4066e commit 33281d8
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/core/lombok/Builder.java
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@
@Retention(SOURCE)
public @interface Default {}

/** @return Name of the method that creates a new builder instance. Default: {@code builder}. */
/** @return Name of the method that creates a new builder instance. Default: {@code builder}. If the empty string, suppress generating the {@code builder} method. */
String builderMethodName() default "builder";

/** @return Name of the method in the builder class that creates an instance of your {@code @Builder}-annotated class. */
Expand Down
27 changes: 21 additions & 6 deletions src/core/lombok/eclipse/handlers/HandleSuperBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,14 @@ public void handle(AnnotationValues<SuperBuilder> annotation, Annotation ast, Ec
if (builderMethodName == null) builderMethodName = "builder";
if (buildMethodName == null) buildMethodName = "build";

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;

boolean toBuilder = superbuilderAnnotation.toBuilder();
Expand All @@ -150,6 +157,8 @@ public void handle(AnnotationValues<SuperBuilder> annotation, Annotation ast, Ec

// Gather all fields of the class that should be set by the builder.
List<EclipseNode> allFields = new ArrayList<EclipseNode>();
List<EclipseNode> nonFinalNonDefaultedFields = null;

boolean valuePresent = (hasAnnotation(lombok.Value.class, tdParent) || hasAnnotation("lombok.experimental.Value", tdParent));
for (EclipseNode fieldNode : HandleConstructor.findAllFields(tdParent, true)) {
FieldDeclaration fd = (FieldDeclaration) fieldNode.get();
Expand Down Expand Up @@ -177,10 +186,9 @@ public void handle(AnnotationValues<SuperBuilder> annotation, Annotation ast, Ec
}

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 (isFinal) continue;
if (nonFinalNonDefaultedFields == null) nonFinalNonDefaultedFields = new ArrayList<EclipseNode>();
nonFinalNonDefaultedFields.add(fieldNode);
}

if (isDefault != null) {
Expand Down Expand Up @@ -386,10 +394,17 @@ public void handle(AnnotationValues<SuperBuilder> annotation, Annotation ast, Ec
}

// Add the builder() method to the annotated class.
if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) {
if (generateBuilderMethod && methodExists(builderMethodName, tdParent, -1) != MemberExistsResult.NOT_EXISTS) generateBuilderMethod = false;
if (generateBuilderMethod) {
MethodDeclaration md = generateBuilderMethod(builderMethodName, builderClassName, builderImplClassName, tdParent, typeParams, ast);
if (md != null) injectMethod(tdParent, md);
}

if (nonFinalNonDefaultedFields != null && generateBuilderMethod) {
for (EclipseNode fieldNode : nonFinalNonDefaultedFields) {
fieldNode.addWarning("@SuperBuilder 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 EclipseNode generateBuilderAbstractClass(EclipseNode tdParent, String builderClass,
Expand Down
2 changes: 1 addition & 1 deletion src/core/lombok/experimental/SuperBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
@Target(TYPE)
@Retention(SOURCE)
public @interface SuperBuilder {
/** @return Name of the method that creates a new builder instance. Default: {@code builder}. */
/** @return Name of the method that creates a new builder instance. Default: {@code builder}. If the empty string, suppress generating the {@code builder} method. */
String builderMethodName() default "builder";

/** @return Name of the method in the builder class that creates an instance of your {@code @Builder}-annotated class. */
Expand Down
23 changes: 20 additions & 3 deletions src/core/lombok/javac/handlers/HandleSuperBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,14 @@ public void handle(AnnotationValues<SuperBuilder> annotation, JCAnnotation ast,
if (builderMethodName == null) builderMethodName = "builder";
if (buildMethodName == null) buildMethodName = "build";

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;

boolean toBuilder = superbuilderAnnotation.toBuilder();
Expand All @@ -125,6 +132,8 @@ public void handle(AnnotationValues<SuperBuilder> annotation, JCAnnotation ast,
// Gather all fields of the class that should be set by the builder.
JCClassDecl td = (JCClassDecl) tdParent.get();
ListBuffer<JavacNode> allFields = new ListBuffer<JavacNode>();
ArrayList<JavacNode> nonFinalNonDefaultedFields = null;

boolean valuePresent = (hasAnnotation(lombok.Value.class, tdParent) || hasAnnotation("lombok.experimental.Value", tdParent));
for (JavacNode fieldNode : HandleConstructor.findAllFields(tdParent, true)) {
JCVariableDecl fd = (JCVariableDecl) fieldNode.get();
Expand All @@ -150,7 +159,8 @@ public void handle(AnnotationValues<SuperBuilder> annotation, JCAnnotation ast,

if (fd.init != null && isDefault == null) {
if (isFinal) continue;
fieldNode.addWarning("@SuperBuilder 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) {
Expand Down Expand Up @@ -347,7 +357,8 @@ public void handle(AnnotationValues<SuperBuilder> annotation, JCAnnotation ast,

// Add the builder() method to the annotated class.
// Allow users to specify their own builder() methods, e.g., to provide default values.
if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) {
if (generateBuilderMethod && methodExists(builderMethodName, tdParent, -1) != MemberExistsResult.NOT_EXISTS) generateBuilderMethod = false;
if (generateBuilderMethod) {
JCMethodDecl builderMethod = generateBuilderMethod(builderMethodName, builderClassName, builderImplClassName, annotationNode, tdParent, typeParams);
recursiveSetGeneratedBy(builderMethod, ast, annotationNode.getContext());
if (builderMethod != null) injectMethod(tdParent, builderMethod);
Expand All @@ -369,6 +380,12 @@ public void handle(AnnotationValues<SuperBuilder> annotation, JCAnnotation ast,
// Should not happen.
}
}

if (nonFinalNonDefaultedFields != null && generateBuilderMethod) {
for (JavacNode fieldNode : nonFinalNonDefaultedFields) {
fieldNode.addWarning("@SuperBuilder 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.");
}
}
}

/**
Expand Down

0 comments on commit 33281d8

Please sign in to comment.