mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-14 04:16:19 +00:00
[wip] reworking how builder works with initialized fields.
This commit is contained in:
1 parent
a2c10c70fa
commit
c63c152884
4 files changed
+47
-6
No files matched your search
@@ -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";
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
Reference in new issue
Block a user