aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReinier Zwitserloot <reinier@zwitserloot.com>2017-03-06 23:33:33 +0100
committerReinier Zwitserloot <reinier@zwitserloot.com>2017-03-07 01:13:00 +0100
commitc63c1528843a3ac591c9fbd2db3732af8824d097 (patch)
tree96cb58ec6c1e05bd214820cf7565fbd133056688
parenta2c10c70fa8e2c8736464a5c3d445e2ca6e8a296 (diff)
downloadlombok-c63c1528843a3ac591c9fbd2db3732af8824d097.tar.gz
lombok-c63c1528843a3ac591c9fbd2db3732af8824d097.tar.bz2
lombok-c63c1528843a3ac591c9fbd2db3732af8824d097.zip
[wip] reworking how builder works with initialized fields.
-rw-r--r--src/core/lombok/Builder.java7
-rw-r--r--src/core/lombok/javac/handlers/HandleBuilder.java19
-rw-r--r--src/core/lombok/javac/handlers/HandleConstructor.java6
-rw-r--r--src/core/lombok/javac/handlers/JavacHandlerUtil.java21
4 files changed, 47 insertions, 6 deletions
diff --git a/src/core/lombok/Builder.java b/src/core/lombok/Builder.java
index 7a965486..a0b8242f 100644
--- a/src/core/lombok/Builder.java
+++ b/src/core/lombok/Builder.java
@@ -107,6 +107,13 @@ import java.lang.annotation.Target;
@Target({TYPE, METHOD, CONSTRUCTOR})
@Retention(SOURCE)
public @interface Builder {
+ /**
+ * Marks a given field as being a 'constant' (initialized by the initializing expression during construction and not eligible to be modified as part of {@code @Builder}.
+ */
+ @Target(FIELD)
+ @Retention(SOURCE)
+ public @interface Constant {}
+
/** Name of the method that creates a new builder instance. Default: {@code builder}. */
String builderMethodName() default "builder";
diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java
index 4c670433..5dde551d 100644
--- a/src/core/lombok/javac/handlers/HandleBuilder.java
+++ b/src/core/lombok/javac/handlers/HandleBuilder.java
@@ -139,12 +139,21 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
ListBuffer<JavacNode> allFields = new ListBuffer<JavacNode>();
@SuppressWarnings("deprecation")
boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation(lombok.experimental.Value.class, parent));
- for (JavacNode fieldNode : HandleConstructor.findAllFields(tdParent)) {
+ for (JavacNode fieldNode : HandleConstructor.findAllFields(tdParent, true)) {
JCVariableDecl fd = (JCVariableDecl) fieldNode.get();
- // final fields with an initializer cannot be written to, so they can't be 'builderized'. Unfortunately presence of @Value makes
- // non-final fields final, but @Value's handler hasn't done this yet, so we have to do this math ourselves.
- // Value will only skip making a field final if it has an explicit @NonFinal annotation, so we check for that.
- if (fd.init != null && valuePresent && !hasAnnotation(NonFinal.class, fieldNode)) continue;
+ boolean isFinal = (fd.mods.flags & Flags.FINAL) != 0 || (valuePresent && !hasAnnotation(NonFinal.class, fieldNode));
+ JavacNode isConstant = findAnnotation(Builder.Constant.class, fieldNode, true);
+
+ if (fd.init != null && isFinal) {
+ if (isConstant != null) continue;
+ }
+
+ if (isConstant != null) {
+ if (!isFinal && fd.init == null) isConstant.addWarning("@Builder.Constant doesn't do anything unless the field has an initializing expression (' = something;') and is final.");
+ else if (!isFinal) isConstant.addWarning("@Builder.Constant doesn't do anything unless the field is final.");
+ else if (fd.init == null) isConstant.addWarning("@Builder.Constant doesn't do anything unless the field has an initializing expression (' = something;').");
+ }
+
BuilderFieldData bfd = new BuilderFieldData();
bfd.rawName = fd.name;
bfd.name = removePrefixFromField(fieldNode);
diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java
index 4e90b639..be4af41c 100644
--- a/src/core/lombok/javac/handlers/HandleConstructor.java
+++ b/src/core/lombok/javac/handlers/HandleConstructor.java
@@ -151,6 +151,10 @@ public class HandleConstructor {
}
public static List<JavacNode> findAllFields(JavacNode typeNode) {
+ return findAllFields(typeNode, false);
+ }
+
+ public static List<JavacNode> findAllFields(JavacNode typeNode, boolean evenFinalInitialized) {
ListBuffer<JavacNode> fields = new ListBuffer<JavacNode>();
for (JavacNode child : typeNode.down()) {
if (child.getKind() != Kind.FIELD) continue;
@@ -162,7 +166,7 @@ public class HandleConstructor {
if ((fieldFlags & Flags.STATIC) != 0) continue;
//Skip initialized final fields
boolean isFinal = (fieldFlags & Flags.FINAL) != 0;
- if (!isFinal || fieldDecl.init == null) fields.append(child);
+ if (evenFinalInitialized || !isFinal || fieldDecl.init == null) fields.append(child);
}
return fields.toList();
}
diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
index 56e666f7..6fa60aac 100644
--- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java
+++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
@@ -191,6 +191,27 @@ public class JavacHandlerUtil {
}
}
+ static JavacNode findAnnotation(Class<? extends Annotation> type, JavacNode node, boolean delete) {
+ if (node == null) return null;
+ if (type == null) return null;
+ switch (node.getKind()) {
+ case ARGUMENT:
+ case FIELD:
+ case LOCAL:
+ case TYPE:
+ case METHOD:
+ for (JavacNode child : node.down()) {
+ if (annotationTypeMatches(type, child)) {
+ if (delete) deleteAnnotationIfNeccessary(child, type);
+ return child;
+ }
+ }
+ // intentional fallthrough
+ default:
+ return null;
+ }
+ }
+
/**
* Checks if the Annotation AST Node provided is likely to be an instance of the provided annotation type.
*