aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/lombok/eclipse/handlers/HandleSuperBuilder.java53
-rw-r--r--test/transform/resource/after-ecj/SuperBuilderWithDefaults.java30
2 files changed, 57 insertions, 26 deletions
diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java
index 6b0275e4..8badb04c 100644
--- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java
+++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java
@@ -48,6 +48,7 @@ import org.eclipse.jdt.internal.compiler.ast.FieldReference;
import org.eclipse.jdt.internal.compiler.ast.IfStatement;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.OperatorIds;
import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
@@ -60,6 +61,7 @@ import org.eclipse.jdt.internal.compiler.ast.ThisReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
+import org.eclipse.jdt.internal.compiler.ast.UnaryExpression;
import org.eclipse.jdt.internal.compiler.ast.Wildcard;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
@@ -95,6 +97,7 @@ import lombok.experimental.SuperBuilder;
public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
private static final char[] CLEAN_FIELD_NAME = "$lombokUnclean".toCharArray();
private static final char[] CLEAN_METHOD_NAME = "$lombokClean".toCharArray();
+ private static final char[] DEFAULT_PREFIX = "$default$".toCharArray();
private static final char[] SET_PREFIX = "$set".toCharArray();
private static final char[] SELF_METHOD_NAME = "self".toCharArray();
@@ -104,6 +107,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
TypeReference type;
char[] rawName;
char[] name;
+ char[] nameOfDefaultProvider;
char[] nameOfSetFlag;
SingularData singularData;
ObtainVia obtainVia;
@@ -177,16 +181,11 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
}
if (isDefault != null) {
+ bfd.nameOfDefaultProvider = prefixWith(DEFAULT_PREFIX, bfd.name);
bfd.nameOfSetFlag = prefixWith(bfd.name, SET_PREFIX);
- // The @Builder annotation removes the initializing expression on the field and moves
- // it to a method called "$default$FIELDNAME". This method is then called upon building.
- // We do NOT do this, because this is unexpected and may lead to bugs when using other
- // constructors (see, e.g., issue #1347).
- // Instead, we keep the init expression and only set a new value in the builder-based
- // constructor if it was set in the builder. Drawback is that the init expression is
- // always executed, even if it was unnecessary because its value is overwritten by the
- // builder.
- // TODO: Once the issue is resolved in @Builder, we can adapt the solution here.
+
+ MethodDeclaration md = HandleBuilder.generateDefaultProvider(bfd.nameOfDefaultProvider, td.typeParameters, fieldNode, ast);
+ if (md != null) injectMethod(tdParent, md);
}
addObtainVia(bfd, fieldNode);
builderFields.add(bfd);
@@ -461,10 +460,10 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
for (BuilderFieldData fieldNode : builderFields) {
char[] fieldName = removePrefixFromField(fieldNode.originalFieldNode);
- FieldReference thisX = new FieldReference(fieldNode.rawName, p);
+ FieldReference fieldInThis = new FieldReference(fieldNode.rawName, p);
int s = (int) (p >> 32);
int e = (int) p;
- thisX.receiver = new ThisReference(s, e);
+ fieldInThis.receiver = new ThisReference(s, e);
Expression assignmentExpr;
if (fieldNode.singularData != null && fieldNode.singularData.getSingularizer() != null) {
@@ -475,16 +474,26 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
long[] positions = new long[] {p, p};
assignmentExpr = new QualifiedNameReference(variableInBuilder, positions, s, e);
}
- Statement assignment = new Assignment(thisX, assignmentExpr, (int) p);
+ Statement assignment = new Assignment(fieldInThis, assignmentExpr, (int) p);
+ statements.add(assignment);
- // In case of @Builder.Default, only set the value if it really was set in the builder.
+ // In case of @Builder.Default, set the value to the default if it was NOT set in the builder.
if (fieldNode.nameOfSetFlag != null) {
- char[][] variableInBuilder = new char[][] {"b".toCharArray(), fieldNode.nameOfSetFlag};
+ char[][] setVariableInBuilder = new char[][] {"b".toCharArray(), fieldNode.nameOfSetFlag};
long[] positions = new long[] {p, p};
- QualifiedNameReference builderRef = new QualifiedNameReference(variableInBuilder, positions, s, e);
- assignment = new IfStatement(builderRef, assignment, s, e);
+ QualifiedNameReference setVariableInBuilderRef = new QualifiedNameReference(setVariableInBuilder, positions, s, e);
+
+ MessageSend inv = new MessageSend();
+ inv.sourceStart = source.sourceStart;
+ inv.sourceEnd = source.sourceEnd;
+ inv.receiver = new SingleNameReference(((TypeDeclaration) typeNode.get()).name, 0L);
+ inv.selector = fieldNode.nameOfDefaultProvider;
+ inv.typeArguments = typeParameterNames(((TypeDeclaration) typeNode.get()).typeParameters);
+
+ assignment = new Assignment(fieldInThis, inv, (int) p);
+ IfStatement ifBlockForDefault = new IfStatement(new UnaryExpression(setVariableInBuilderRef, OperatorIds.NOT), assignment, s, e);
+ statements.add(ifBlockForDefault);
}
- statements.add(assignment);
Annotation[] nonNulls = findAnnotations((FieldDeclaration)fieldNode.originalFieldNode.get(), NON_NULL_PATTERN);
if (nonNulls.length != 0) {
@@ -817,6 +826,16 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
return result;
}
+ private TypeReference[] typeParameterNames(TypeParameter[] typeParameters) {
+ if (typeParameters == null) return null;
+
+ TypeReference[] trs = new TypeReference[typeParameters.length];
+ for (int i = 0; i < trs.length; i++) {
+ trs[i] = new SingleTypeReference(typeParameters[i].name, 0);
+ }
+ return trs;
+ }
+
private EclipseNode findInnerClass(EclipseNode parent, String name) {
char[] c = name.toCharArray();
for (EclipseNode child : parent.down()) {
diff --git a/test/transform/resource/after-ecj/SuperBuilderWithDefaults.java b/test/transform/resource/after-ecj/SuperBuilderWithDefaults.java
index f0e3d8be..731bd9f2 100644
--- a/test/transform/resource/after-ecj/SuperBuilderWithDefaults.java
+++ b/test/transform/resource/after-ecj/SuperBuilderWithDefaults.java
@@ -36,14 +36,22 @@ public class SuperBuilderWithDefaults {
return new Parent<N>(this);
}
}
- private @lombok.Builder.Default long millis = System.currentTimeMillis();
- private @lombok.Builder.Default N numberField = null;
+ private @lombok.Builder.Default long millis;
+ private @lombok.Builder.Default N numberField;
+ private static @java.lang.SuppressWarnings("all") <N extends Number>long $default$millis() {
+ return System.currentTimeMillis();
+ }
+ private static @java.lang.SuppressWarnings("all") <N extends Number>N $default$numberField() {
+ return null;
+ }
protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder<N, ?, ?> b) {
super();
- if (b.millis$set)
- this.millis = b.millis;
- if (b.numberField$set)
- this.numberField = b.numberField;
+ this.millis = b.millis;
+ if ((! b.millis$set))
+ this.millis = Parent.<N>$default$millis();
+ this.numberField = b.numberField;
+ if ((! b.numberField$set))
+ this.numberField = Parent.<N>$default$numberField();
}
public static @java.lang.SuppressWarnings("all") <N extends Number>ParentBuilder<N, ?, ?> builder() {
return new ParentBuilderImpl<N>();
@@ -78,11 +86,15 @@ public class SuperBuilderWithDefaults {
return new Child(this);
}
}
- private @lombok.Builder.Default double doubleField = Math.PI;
+ private @lombok.Builder.Default double doubleField;
+ private static @java.lang.SuppressWarnings("all") double $default$doubleField() {
+ return Math.PI;
+ }
protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder<?, ?> b) {
super(b);
- if (b.doubleField$set)
- this.doubleField = b.doubleField;
+ this.doubleField = b.doubleField;
+ if ((! b.doubleField$set))
+ this.doubleField = Child.$default$doubleField();
}
public static @java.lang.SuppressWarnings("all") ChildBuilder<?, ?> builder() {
return new ChildBuilderImpl();