aboutsummaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/lombok/bytecode/AsmUtil.java2
-rw-r--r--src/core/lombok/bytecode/PreventNullAnalysisRemover.java4
-rw-r--r--src/core/lombok/bytecode/SneakyThrowsRemover.java4
-rw-r--r--src/core/lombok/core/AST.java3
-rw-r--r--src/core/lombok/core/AnnotationProcessor.java6
-rw-r--r--src/core/lombok/core/AnnotationValues.java3
-rw-r--r--src/core/lombok/core/Main.java8
-rw-r--r--src/core/lombok/core/handlers/HandlerUtil.java3
-rw-r--r--src/core/lombok/eclipse/EclipseAST.java3
-rw-r--r--src/core/lombok/eclipse/TransformEclipseAST.java3
-rw-r--r--src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java9
-rw-r--r--src/core/lombok/eclipse/handlers/HandleBuilder.java47
-rw-r--r--src/core/lombok/eclipse/handlers/HandleConstructor.java1
-rw-r--r--src/core/lombok/eclipse/handlers/HandleSuperBuilder.java271
-rw-r--r--src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java2
-rw-r--r--src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java4
-rw-r--r--src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java2
-rw-r--r--src/core/lombok/experimental/SuperBuilder.java23
-rw-r--r--src/core/lombok/javac/CompilerMessageSuppressor.java9
-rw-r--r--src/core/lombok/javac/Javac6BasedLombokOptions.java5
-rw-r--r--src/core/lombok/javac/JavacAST.java52
-rw-r--r--src/core/lombok/javac/JavacResolution.java11
-rw-r--r--src/core/lombok/javac/apt/LombokFileObjects.java7
-rw-r--r--src/core/lombok/javac/apt/LombokProcessor.java68
-rw-r--r--src/core/lombok/javac/apt/Processor.java8
-rw-r--r--src/core/lombok/javac/handlers/HandleBuilder.java26
-rw-r--r--src/core/lombok/javac/handlers/HandleSuperBuilder.java293
-rw-r--r--src/core/lombok/javac/handlers/JavacHandlerUtil.java14
28 files changed, 651 insertions, 240 deletions
diff --git a/src/core/lombok/bytecode/AsmUtil.java b/src/core/lombok/bytecode/AsmUtil.java
index e3d33efa..42bf9700 100644
--- a/src/core/lombok/bytecode/AsmUtil.java
+++ b/src/core/lombok/bytecode/AsmUtil.java
@@ -37,7 +37,7 @@ class AsmUtil {
ClassReader reader = new ClassReader(byteCode);
ClassWriter writer = new FixedClassWriter(reader, 0);
- ClassVisitor visitor = new ClassVisitor(Opcodes.ASM6, writer) {
+ ClassVisitor visitor = new ClassVisitor(Opcodes.ASM7, writer) {
@Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
return new JSRInlinerAdapter(super.visitMethod(access, name, desc, signature, exceptions), access, name, desc, signature, exceptions);
}
diff --git a/src/core/lombok/bytecode/PreventNullAnalysisRemover.java b/src/core/lombok/bytecode/PreventNullAnalysisRemover.java
index c06f2d7c..20572e22 100644
--- a/src/core/lombok/bytecode/PreventNullAnalysisRemover.java
+++ b/src/core/lombok/bytecode/PreventNullAnalysisRemover.java
@@ -50,7 +50,7 @@ public class PreventNullAnalysisRemover implements PostCompilerTransformation {
class PreventNullAnalysisVisitor extends MethodVisitor {
PreventNullAnalysisVisitor(MethodVisitor mv) {
- super(Opcodes.ASM6, mv);
+ super(Opcodes.ASM7, mv);
}
@Override public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
@@ -68,7 +68,7 @@ public class PreventNullAnalysisRemover implements PostCompilerTransformation {
}
}
- reader.accept(new ClassVisitor(Opcodes.ASM6, writer) {
+ reader.accept(new ClassVisitor(Opcodes.ASM7, writer) {
@Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
return new PreventNullAnalysisVisitor(super.visitMethod(access, name, desc, signature, exceptions));
}
diff --git a/src/core/lombok/bytecode/SneakyThrowsRemover.java b/src/core/lombok/bytecode/SneakyThrowsRemover.java
index a2ee59ea..037cb109 100644
--- a/src/core/lombok/bytecode/SneakyThrowsRemover.java
+++ b/src/core/lombok/bytecode/SneakyThrowsRemover.java
@@ -52,7 +52,7 @@ public class SneakyThrowsRemover implements PostCompilerTransformation {
class SneakyThrowsRemoverVisitor extends MethodVisitor {
SneakyThrowsRemoverVisitor(MethodVisitor mv) {
- super(Opcodes.ASM6, mv);
+ super(Opcodes.ASM7, mv);
}
private boolean methodInsnQueued = false;
@@ -177,7 +177,7 @@ public class SneakyThrowsRemover implements PostCompilerTransformation {
}
}
- reader.accept(new ClassVisitor(Opcodes.ASM5, writer) {
+ reader.accept(new ClassVisitor(Opcodes.ASM7, writer) {
@Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
return new SneakyThrowsRemoverVisitor(super.visitMethod(access, name, desc, signature, exceptions));
}
diff --git a/src/core/lombok/core/AST.java b/src/core/lombok/core/AST.java
index fe7a4330..afbba1e8 100644
--- a/src/core/lombok/core/AST.java
+++ b/src/core/lombok/core/AST.java
@@ -39,6 +39,7 @@ import java.util.concurrent.ConcurrentMap;
import lombok.core.configuration.ConfigurationKey;
import lombok.core.debug.HistogramTracker;
+import lombok.permit.Permit;
/**
* Lombok wraps the AST produced by a target platform into its own AST system, mostly because both Eclipse and javac
@@ -252,7 +253,7 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>,
}
if (shouldDrill(c, t, f.getName())) {
- f.setAccessible(true);
+ Permit.setAccessible(f);
fields.add(new FieldAccess(f, dim));
}
}
diff --git a/src/core/lombok/core/AnnotationProcessor.java b/src/core/lombok/core/AnnotationProcessor.java
index 293bfef6..363952a4 100644
--- a/src/core/lombok/core/AnnotationProcessor.java
+++ b/src/core/lombok/core/AnnotationProcessor.java
@@ -46,6 +46,7 @@ import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
import lombok.patcher.ClassRootFinder;
+import lombok.permit.Permit;
@SupportedAnnotationTypes("*")
public class AnnotationProcessor extends AbstractProcessor {
@@ -82,8 +83,7 @@ public class AnnotationProcessor extends AbstractProcessor {
for (Class<?> procEnvClass = procEnv.getClass(); procEnvClass != null; procEnvClass = procEnvClass.getSuperclass()) {
try {
- Field field = procEnvClass.getDeclaredField("delegate");
- field.setAccessible(true);
+ Field field = Permit.getField(procEnvClass, "delegate");
Object delegate = field.get(procEnv);
return tryRecursivelyObtainJavacProcessingEnvironment((ProcessingEnvironment) delegate);
@@ -136,7 +136,7 @@ public class AnnotationProcessor extends AbstractProcessor {
ClassLoader environmentClassLoader = procEnv.getClass().getClassLoader();
if (environmentClassLoader != null && environmentClassLoader.getClass().getCanonicalName().equals("org.codehaus.plexus.compiler.javac.IsolatedClassLoader")) {
if (!ClassLoader_lombokAlreadyAddedTo.getAndSet(environmentClassLoader, true)) {
- Method m = environmentClassLoader.getClass().getDeclaredMethod("addURL", URL.class);
+ Method m = Permit.getMethod(environmentClassLoader.getClass(), "addURL", URL.class);
URL selfUrl = new File(ClassRootFinder.findClassRootOfClass(AnnotationProcessor.class)).toURI().toURL();
m.invoke(environmentClassLoader, selfUrl);
}
diff --git a/src/core/lombok/core/AnnotationValues.java b/src/core/lombok/core/AnnotationValues.java
index a24330fa..eec5abd8 100644
--- a/src/core/lombok/core/AnnotationValues.java
+++ b/src/core/lombok/core/AnnotationValues.java
@@ -33,6 +33,7 @@ import java.util.List;
import java.util.Map;
import lombok.core.AST.Kind;
+import lombok.permit.Permit;
/**
* Represents a single annotation in a source file and can be used to query the parameters present on it.
@@ -210,7 +211,7 @@ public class AnnotationValues<A extends Annotation> {
public <T> T getDefaultIf(String methodName, Class<T> type, T defaultValue) {
try {
- return type.cast(type.getMethod(methodName).getDefaultValue());
+ return type.cast(Permit.getMethod(type, methodName).getDefaultValue());
} catch (Exception e) {
return defaultValue;
}
diff --git a/src/core/lombok/core/Main.java b/src/core/lombok/core/Main.java
index 6952ab78..47afaefd 100644
--- a/src/core/lombok/core/Main.java
+++ b/src/core/lombok/core/Main.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2012 The Project Lombok Authors.
+ * Copyright (C) 2009-2018 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -41,7 +41,9 @@ public class Main {
Thread.currentThread().setContextClassLoader(Main.class.getClassLoader());
int err = new Main(SpiLoadUtil.readAllFromIterator(
SpiLoadUtil.findServices(LombokApp.class)), Arrays.asList(args)).go();
- System.exit(err);
+ if (err != 0) {
+ System.exit(err);
+ }
}
@ProviderFor(LombokApp.class)
@@ -143,7 +145,7 @@ public class Main {
out.println("------------------------------");
}
out.println("projectlombok.org " + Version.getFullVersion());
- out.println("Copyright (C) 2009-2015 The Project Lombok Authors.");
+ out.println("Copyright (C) 2009-2018 The Project Lombok Authors.");
out.println("Run 'lombok license' to see the lombok license agreement.");
out.println();
out.println("Run lombok without any parameters to start the graphical installer.");
diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java
index 296b70b4..ac91447d 100644
--- a/src/core/lombok/core/handlers/HandlerUtil.java
+++ b/src/core/lombok/core/handlers/HandlerUtil.java
@@ -85,6 +85,7 @@ public class HandlerUtil {
"org.jetbrains.annotations.NotNull",
"android.support.annotation.NonNull",
"org.eclipse.jdt.annotation.NonNull",
+ "org.springframework.lang.NonNull"
}));
BASE_COPYABLE_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] {
"lombok.NonNull",
@@ -93,6 +94,7 @@ public class HandlerUtil {
"org.jetbrains.annotations.NotNull",
"android.support.annotation.NonNull",
"org.eclipse.jdt.annotation.NonNull",
+ "org.springframework.lang.NonNull",
"javax.annotation.Nullable",
"javax.annotation.CheckForNull",
"edu.umd.cs.findbugs.annotations.UnknownNullness",
@@ -100,6 +102,7 @@ public class HandlerUtil {
"org.jetbrains.annotations.Nullable",
"android.support.annotation.Nullable",
"org.eclipse.jdt.annotation.Nullable",
+ "org.springframework.lang.Nullable"
}));
}
diff --git a/src/core/lombok/eclipse/EclipseAST.java b/src/core/lombok/eclipse/EclipseAST.java
index 7cd2e400..1ba26338 100644
--- a/src/core/lombok/eclipse/EclipseAST.java
+++ b/src/core/lombok/eclipse/EclipseAST.java
@@ -34,6 +34,7 @@ import lombok.Lombok;
import lombok.core.AST;
import lombok.core.LombokImmutableList;
import lombok.eclipse.handlers.EclipseHandlerUtil;
+import lombok.permit.Permit;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Path;
@@ -497,7 +498,7 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> {
Throwable problem_ = null;
Method m = null;
try {
- m = EclipseAstProblemView.class.getMethod("addProblemToCompilationResult", char[].class, Class.forName(COMPILATIONRESULT_TYPE), boolean.class, String.class, int.class, int.class);
+ m = Permit.getMethod(EclipseAstProblemView.class, "addProblemToCompilationResult", char[].class, Class.forName(COMPILATIONRESULT_TYPE), boolean.class, String.class, int.class, int.class);
} catch (Throwable t) {
// That's problematic, but as long as no local classes are used we don't actually need it.
// Better fail on local classes than crash altogether.
diff --git a/src/core/lombok/eclipse/TransformEclipseAST.java b/src/core/lombok/eclipse/TransformEclipseAST.java
index 323fc171..e5edba64 100644
--- a/src/core/lombok/eclipse/TransformEclipseAST.java
+++ b/src/core/lombok/eclipse/TransformEclipseAST.java
@@ -30,6 +30,7 @@ import lombok.core.LombokConfiguration;
import lombok.core.debug.DebugSnapshotStore;
import lombok.core.debug.HistogramTracker;
import lombok.patcher.Symbols;
+import lombok.permit.Permit;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Annotation;
@@ -90,7 +91,7 @@ public class TransformEclipseAST {
disableLombok = true;
}
try {
- f = CompilationUnitDeclaration.class.getDeclaredField("$lombokAST");
+ f = Permit.getField(CompilationUnitDeclaration.class, "$lombokAST");
} catch (Throwable t) {
//I guess we're in an ecj environment; we'll just not cache stuff then.
}
diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
index 5d582aad..c69b3d0f 100644
--- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
+++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
@@ -56,6 +56,7 @@ import lombok.eclipse.EclipseAST;
import lombok.eclipse.EclipseNode;
import lombok.experimental.Accessors;
import lombok.experimental.Tolerate;
+import lombok.permit.Permit;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
@@ -337,9 +338,7 @@ public class EclipseHandlerUtil {
private static Field getField(Class<?> c, String fName) {
try {
- Field f = c.getDeclaredField(fName);
- f.setAccessible(true);
- return f;
+ return Permit.getField(c, fName);
} catch (Exception e) {
return null;
}
@@ -1931,12 +1930,12 @@ public class EclipseHandlerUtil {
Constructor<IntLiteral> intLiteralConstructor_ = null;
Method intLiteralFactoryMethod_ = null;
try {
- intLiteralConstructor_ = IntLiteral.class.getConstructor(parameterTypes);
+ intLiteralConstructor_ = Permit.getConstructor(IntLiteral.class, parameterTypes);
} catch (Throwable ignore) {
// probably eclipse 3.7++
}
try {
- intLiteralFactoryMethod_ = IntLiteral.class.getMethod("buildIntLiteral", parameterTypes);
+ intLiteralFactoryMethod_ = Permit.getMethod(IntLiteral.class, "buildIntLiteral", parameterTypes);
} catch (Throwable ignore) {
// probably eclipse versions before 3.7
}
diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java
index 86c1da42..0ce1436d 100644
--- a/src/core/lombok/eclipse/handlers/HandleBuilder.java
+++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java
@@ -25,6 +25,7 @@ import static lombok.eclipse.Eclipse.*;
import static lombok.core.handlers.HandlerUtil.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
+import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -46,6 +47,7 @@ import org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.FieldReference;
import org.eclipse.jdt.internal.compiler.ast.IfStatement;
+import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
@@ -105,7 +107,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
return ((Boolean) expr).booleanValue();
}
- private static class BuilderFieldData {
+ static class BuilderFieldData {
Annotation[] annotations;
TypeReference type;
char[] rawName;
@@ -443,6 +445,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
cleanDecl.declarationSourceEnd = -1;
cleanDecl.modifiers = ClassFileConstants.AccPrivate;
cleanDecl.type = TypeReference.baseTypeReference(TypeIds.T_boolean, 0);
+ cleanDecl.traverse(new SetGeneratedByVisitor(ast), (MethodScope) null);
injectFieldAndMarkGenerated(builderType, cleanDecl);
}
@@ -502,15 +505,12 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
}
}
- private static final char[] EMPTY_LIST = "emptyList".toCharArray();
+ private static final char[] BUILDER_TEMP_VAR = {'b', 'u', 'i', 'l', 'd', 'e', 'r'};
private MethodDeclaration generateToBuilderMethod(String methodName, String builderClassName, EclipseNode type, TypeParameter[] typeParams, List<BuilderFieldData> builderFields, boolean fluent, ASTNode source) {
- // return new ThingieBuilder<A, B>().setA(this.a).setB(this.b);
-
int pS = source.sourceStart, pE = source.sourceEnd;
long p = (long) pS << 32 | pE;
- MethodDeclaration out = new MethodDeclaration(
- ((CompilationUnitDeclaration) type.top().get()).compilationResult);
+ MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
out.selector = methodName.toCharArray();
out.modifiers = ClassFileConstants.AccPublic;
out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
@@ -519,6 +519,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
invoke.type = namePlusTypeParamsToTypeReference(builderClassName.toCharArray(), typeParams, p);
Expression receiver = invoke;
+ List<Statement> statements = null;
for (BuilderFieldData bfd : builderFields) {
char[] setterName = fluent ? bfd.name : HandlerUtil.buildAccessorName("set", new String(bfd.name)).toCharArray();
MessageSend ms = new MessageSend();
@@ -552,22 +553,34 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
tgt[i] = obtainExpr;
}
}
+
+ ms.selector = setterName;
if (bfd.singularData == null) {
ms.arguments = tgt;
+ ms.receiver = receiver;
+ receiver = ms;
} else {
- Expression ifNull = new EqualExpression(tgt[0], new NullLiteral(0, 0), OperatorIds.EQUAL_EQUAL);
- MessageSend emptyList = new MessageSend();
- emptyList.receiver = generateQualifiedNameRef(source, TypeConstants.JAVA, TypeConstants.UTIL, "Collections".toCharArray());
- emptyList.selector = EMPTY_LIST;
- emptyList.typeArguments = bfd.singularData.getSingularizer().createTypeArgs(bfd.singularData.getTypeArgs().size(), false, type, bfd.singularData.getTypeArgs());
- ms.arguments = new Expression[] {new ConditionalExpression(ifNull, emptyList, tgt[1])};
+ ms.arguments = new Expression[] {tgt[1]};
+ ms.receiver = new SingleNameReference(BUILDER_TEMP_VAR, p);
+ EqualExpression isNotNull = new EqualExpression(tgt[0], new NullLiteral(pS, pE), OperatorIds.NOT_EQUAL);
+ if (statements == null) statements = new ArrayList<Statement>();
+ statements.add(new IfStatement(isNotNull, ms, pS, pE));
}
- ms.receiver = receiver;
- ms.selector = setterName;
- receiver = ms;
}
- out.statements = new Statement[] {new ReturnStatement(receiver, pS, pE)};
+ if (statements != null) {
+ out.statements = new Statement[statements.size() + 2];
+ for (int i = 0; i < statements.size(); i++) out.statements[i + 1] = statements.get(i);
+ LocalDeclaration b = new LocalDeclaration(BUILDER_TEMP_VAR, pS, pE);
+ out.statements[0] = b;
+ b.modifiers |= Modifier.FINAL;
+ b.type = namePlusTypeParamsToTypeReference(builderClassName.toCharArray(), typeParams, p);
+ b.type.sourceStart = pS; b.type.sourceEnd = pE;
+ b.initialization = receiver;
+ out.statements[out.statements.length - 1] = new ReturnStatement(new SingleNameReference(BUILDER_TEMP_VAR, p), pS, pE);
+ } else {
+ out.statements = new Statement[] {new ReturnStatement(receiver, pS, pE)};
+ }
out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) type.get()).scope);
return out;
@@ -627,7 +640,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
inv.typeArguments = typeParameterNames(((TypeDeclaration) type.get()).typeParameters);
args.add(new ConditionalExpression(
- new SingleNameReference(bfd.nameOfSetFlag, 0L),
+ new SingleNameReference(bfd.nameOfSetFlag, 0L),
new SingleNameReference(bfd.name, 0L),
inv));
} else {
diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java
index cb07115a..82859e4b 100644
--- a/src/core/lombok/eclipse/handlers/HandleConstructor.java
+++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java
@@ -484,6 +484,7 @@ public class HandleConstructor {
for (EclipseNode node : type.down()) {
if (node.getKind() != Kind.FIELD) continue top;
FieldDeclaration fd = (FieldDeclaration) node.get();
+ if (fd.initialization != null) continue top;
if ((fd.modifiers & ClassFileConstants.AccFinal) == 0) continue top;
if ((fd.modifiers & ClassFileConstants.AccStatic) != 0) continue top;
for (EclipseNode ftp : fieldsToParam) if (node == ftp) continue top;
diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java
index 3070f1dc..9a3275c2 100644
--- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java
+++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java
@@ -39,7 +39,9 @@ import org.eclipse.jdt.internal.compiler.ast.Annotation;
import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.Assignment;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression;
import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.EqualExpression;
import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
@@ -48,6 +50,8 @@ 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.NullLiteral;
+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;
@@ -56,6 +60,7 @@ import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.Statement;
+import org.eclipse.jdt.internal.compiler.ast.SuperReference;
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
@@ -87,6 +92,7 @@ import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer;
import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData;
import lombok.eclipse.handlers.EclipseSingularsRecipes.StatementMaker;
import lombok.eclipse.handlers.EclipseSingularsRecipes.TypeReferenceMaker;
+import lombok.eclipse.handlers.HandleBuilder.BuilderFieldData;
import lombok.experimental.NonFinal;
import lombok.experimental.SuperBuilder;
@@ -98,41 +104,36 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
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();
+ private static final String TO_BUILDER_METHOD_NAME_STRING = "toBuilder";
+ private static final char[] TO_BUILDER_METHOD_NAME = TO_BUILDER_METHOD_NAME_STRING.toCharArray();
+ private static final char[] FILL_VALUES_METHOD_NAME = "$fillValuesFrom".toCharArray();
+ private static final char[] FILL_VALUES_STATIC_METHOD_NAME = "$fillValuesFromInstanceIntoBuilder".toCharArray();
+ private static final char[] EMPTY_LIST = "emptyList".toCharArray();
+ private static final char[] INSTANCE_VARIABLE_NAME = "instance".toCharArray();
+ private static final String BUILDER_VARIABLE_NAME_STRING = "b";
+ private static final char[] BUILDER_VARIABLE_NAME = BUILDER_VARIABLE_NAME_STRING.toCharArray();
private static final AbstractMethodDeclaration[] EMPTY_METHODS = {};
- private static class BuilderFieldData {
- Annotation[] annotations;
- TypeReference type;
- char[] rawName;
- char[] name;
- char[] nameOfDefaultProvider;
- char[] nameOfSetFlag;
- SingularData singularData;
- ObtainVia obtainVia;
- EclipseNode obtainViaNode;
- EclipseNode originalFieldNode;
-
- List<EclipseNode> createdFields = new ArrayList<EclipseNode>();
- }
-
@Override
public void handle(AnnotationValues<SuperBuilder> annotation, Annotation ast, EclipseNode annotationNode) {
handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.SUPERBUILDER_FLAG_USAGE, "@SuperBuilder");
long p = (long) ast.sourceStart << 32 | ast.sourceEnd;
- SuperBuilder builderInstance = annotation.getInstance();
+ SuperBuilder superbuilderAnnotation = annotation.getInstance();
- String builderMethodName = builderInstance.builderMethodName();
- String buildMethodName = builderInstance.buildMethodName();
+ String builderMethodName = superbuilderAnnotation.builderMethodName();
+ String buildMethodName = superbuilderAnnotation.buildMethodName();
if (builderMethodName == null) builderMethodName = "builder";
if (buildMethodName == null) buildMethodName = "build";
if (!checkName("builderMethodName", builderMethodName, annotationNode)) return;
if (!checkName("buildMethodName", buildMethodName, annotationNode)) return;
-
+
+ boolean toBuilder = superbuilderAnnotation.toBuilder();
+
EclipseNode tdParent = annotationNode.up();
java.util.List<BuilderFieldData> builderFields = new ArrayList<BuilderFieldData>();
@@ -258,14 +259,28 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
generateBuilderBasedConstructor(tdParent, typeParams, builderFields, annotationNode, builderClassName,
superclassBuilderClass != null);
- // Create the abstract builder class.
+ // Create the abstract builder class, or reuse an existing one.
EclipseNode builderType = findInnerClass(tdParent, builderClassName);
if (builderType == null) {
builderType = generateBuilderAbstractClass(tdParent, builderClassName, superclassBuilderClass,
typeParams, ast, classGenericName, builderGenericName);
} else {
- annotationNode.addError("@SuperBuilder does not support customized builders. Use @Builder instead.");
- return;
+ TypeDeclaration builderTypeDeclaration = (TypeDeclaration) builderType.get();
+ if ((builderTypeDeclaration.modifiers & (ClassFileConstants.AccStatic | ClassFileConstants.AccAbstract)) == 0) {
+ annotationNode.addError("Existing Builder must be an abstract static inner class.");
+ return;
+ }
+ sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderType, annotationNode);
+ // Generate errors for @Singular BFDs that have one already defined node.
+ for (BuilderFieldData bfd : builderFields) {
+ SingularData sd = bfd.singularData;
+ if (sd == null) continue;
+ EclipseSingularizer singularizer = sd.getSingularizer();
+ if (singularizer == null) continue;
+ if (singularizer.checkForAlreadyExistingNodesAndGenerateError(builderType, sd)) {
+ bfd.singularData = null;
+ }
+ }
}
// Check validity of @ObtainVia fields, and add check if adding cleaning for @Singular is necessary.
@@ -297,7 +312,14 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
cleanDecl.type = TypeReference.baseTypeReference(TypeIds.T_boolean, 0);
injectFieldAndMarkGenerated(builderType, cleanDecl);
}
-
+
+ if (toBuilder) {
+ // Generate $fillValuesFrom() method in the abstract builder.
+ injectMethod(builderType, generateFillValuesMethod(tdParent, superclassBuilderClass != null, builderGenericName, classGenericName, builderClassName, typeParams));
+ // Generate $fillValuesFromInstanceIntoBuilder() method in the builder implementation class.
+ injectMethod(builderType, generateStaticFillValuesMethod(tdParent, builderClassName, typeParams, builderFields, ast));
+ }
+
// Generate abstract self() and build() methods in the abstract builder.
injectMethod(builderType, generateAbstractSelfMethod(tdParent, superclassBuilderClass != null, builderGenericName));
injectMethod(builderType, generateAbstractBuildMethod(tdParent, buildMethodName, superclassBuilderClass != null, classGenericName, ast));
@@ -324,23 +346,44 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
if (addCleaning) injectMethod(builderType, generateCleanMethod(builderFields, builderType, ast));
- if ((td.modifiers & ClassFileConstants.AccAbstract) != 0) {
+ boolean isAbstract = (td.modifiers & ClassFileConstants.AccAbstract) != 0;
+ if (isAbstract) {
// Only non-abstract classes get the Builder implementation.
return;
}
- // Create the builder implementation class.
+ // Create the builder implementation class, or reuse an existing one.
EclipseNode builderImplType = findInnerClass(tdParent, builderImplClassName);
if (builderImplType == null) {
builderImplType = generateBuilderImplClass(tdParent, builderImplClassName, builderClassName, typeParams, ast);
} else {
- annotationNode.addError("@SuperBuilder does not support customized builders. Use @Builder instead.");
- return;
+ TypeDeclaration builderImplTypeDeclaration = (TypeDeclaration) builderImplType.get();
+ if ((builderImplTypeDeclaration.modifiers & ClassFileConstants.AccAbstract) != 0 ||
+ (builderImplTypeDeclaration.modifiers & ClassFileConstants.AccStatic) == 0) {
+ annotationNode.addError("Existing BuilderImpl must be a non-abstract static inner class.");
+ return;
+ }
+ sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderImplType, annotationNode);
}
-
+
+ if (toBuilder) {
+ // Add the toBuilder() method to the annotated class.
+ switch (methodExists(TO_BUILDER_METHOD_NAME_STRING, tdParent, 0)) {
+ case EXISTS_BY_USER:
+ annotationNode.addWarning("Not generating toBuilder() as it already exists.");
+ break;
+ case NOT_EXISTS:
+ injectMethod(tdParent, generateToBuilderMethod(builderClassName, builderImplClassName, tdParent, typeParams, ast));
+ default:
+ // Should not happen.
+ }
+ }
+
// Create the self() and build() methods in the BuilderImpl.
injectMethod(builderImplType, generateSelfMethod(builderImplType, typeParams, p));
- injectMethod(builderImplType, generateBuildMethod(tdParent, buildMethodName, returnType, ast));
+ if (methodExists(buildMethodName, builderImplType, -1) == MemberExistsResult.NOT_EXISTS) {
+ injectMethod(builderImplType, generateBuildMethod(tdParent, buildMethodName, returnType, ast));
+ }
// Add the builder() method to the annotated class.
if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) {
@@ -441,7 +484,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
constructor.selector = typeDeclaration.name;
if (callBuilderBasedSuperConstructor) {
constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.Super);
- constructor.constructorCall.arguments = new Expression[] {new SingleNameReference("b".toCharArray(), p)};
+ constructor.constructorCall.arguments = new Expression[] {new SingleNameReference(BUILDER_VARIABLE_NAME, p)};
} else {
constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper);
}
@@ -455,7 +498,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
TypeReference[] wildcards = new TypeReference[] {new Wildcard(Wildcard.UNBOUND), new Wildcard(Wildcard.UNBOUND)};
TypeReference builderType = new ParameterizedSingleTypeReference(builderClassName.toCharArray(), mergeToTypeReferences(typeParams, wildcards), 0, p);
- constructor.arguments = new Argument[] {new Argument("b".toCharArray(), p, builderType, Modifier.FINAL)};
+ constructor.arguments = new Argument[] {new Argument(BUILDER_VARIABLE_NAME, p, builderType, Modifier.FINAL)};
List<Statement> statements = new ArrayList<Statement>();
@@ -468,10 +511,10 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
Expression assignmentExpr;
if (fieldNode.singularData != null && fieldNode.singularData.getSingularizer() != null) {
- fieldNode.singularData.getSingularizer().appendBuildCode(fieldNode.singularData, typeNode, statements, fieldNode.name, "b");
+ fieldNode.singularData.getSingularizer().appendBuildCode(fieldNode.singularData, typeNode, statements, fieldNode.name, BUILDER_VARIABLE_NAME_STRING);
assignmentExpr = new SingleNameReference(fieldNode.name, p);
} else {
- char[][] variableInBuilder = new char[][] {"b".toCharArray(), fieldName};
+ char[][] variableInBuilder = new char[][] {BUILDER_VARIABLE_NAME, fieldName};
long[] positions = new long[] {p, p};
assignmentExpr = new QualifiedNameReference(variableInBuilder, positions, s, e);
}
@@ -479,7 +522,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
// In case of @Builder.Default, set the value to the default if it was NOT set in the builder.
if (fieldNode.nameOfSetFlag != null) {
- char[][] setVariableInBuilder = new char[][] {"b".toCharArray(), fieldNode.nameOfSetFlag};
+ char[][] setVariableInBuilder = new char[][] {BUILDER_VARIABLE_NAME, fieldNode.nameOfSetFlag};
long[] positions = new long[] {p, p};
QualifiedNameReference setVariableInBuilderRef = new QualifiedNameReference(setVariableInBuilder, positions, s, e);
@@ -533,6 +576,166 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
return out;
}
+ /**
+ * Generates a <code>toBuilder()</code> method in the annotated class that looks like this:
+ * <pre>
+ * public ParentBuilder&lt;?, ?&gt; toBuilder() {
+ * return new <i>Foobar</i>BuilderImpl().$fillValuesFrom(this);
+ * }
+ * </pre>
+ */
+ private MethodDeclaration generateToBuilderMethod(String builderClassName, String builderImplClassName, EclipseNode type, TypeParameter[] typeParams, ASTNode source) {
+ int pS = source.sourceStart, pE = source.sourceEnd;
+ long p = (long) pS << 32 | pE;
+
+ MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
+ out.selector = TO_BUILDER_METHOD_NAME;
+ out.modifiers = ClassFileConstants.AccPublic;
+ out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
+
+ TypeReference[] wildcards = new TypeReference[] {new Wildcard(Wildcard.UNBOUND), new Wildcard(Wildcard.UNBOUND) };
+ out.returnType = new ParameterizedSingleTypeReference(builderClassName.toCharArray(), mergeToTypeReferences(typeParams, wildcards), 0, p);
+
+ AllocationExpression newClass = new AllocationExpression();
+ newClass.type = namePlusTypeParamsToTypeReference(builderImplClassName.toCharArray(), typeParams, p);
+ MessageSend invokeFillMethod = new MessageSend();
+ invokeFillMethod.receiver = newClass;
+ invokeFillMethod.selector = FILL_VALUES_METHOD_NAME;
+ invokeFillMethod.arguments = new Expression[] {new ThisReference(0, 0)};
+ out.statements = new Statement[] {new ReturnStatement(invokeFillMethod, pS, pE)};
+
+ out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) type.get()).scope);
+ return out;
+ }
+
+ /**
+ * Generates a <code>$fillValuesFrom()</code> method in the abstract builder class that looks
+ * like this:
+ * <pre>
+ * protected B $fillValuesFrom(final C instance) {
+ * super.$fillValuesFrom(instance);
+ * FoobarBuilderImpl.$fillValuesFromInstanceIntoBuilder(instance, this);
+ * return self();
+ * }
+ * </pre>
+ */
+ private MethodDeclaration generateFillValuesMethod(EclipseNode tdParent, boolean inherited, String builderGenericName, String classGenericName, String builderClassName, TypeParameter[] typeParams) {
+ MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult);
+ out.selector = FILL_VALUES_METHOD_NAME;
+ out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
+ out.modifiers = ClassFileConstants.AccProtected;
+ if (inherited) out.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, tdParent.get())};
+ out.returnType = new SingleTypeReference(builderGenericName.toCharArray(), 0);
+
+ TypeReference builderType = new SingleTypeReference(classGenericName.toCharArray(), 0);
+ out.arguments = new Argument[] {new Argument(INSTANCE_VARIABLE_NAME, 0, builderType, Modifier.FINAL)};
+
+ List<Statement> body = new ArrayList<Statement>();
+
+ if (inherited) {
+ // Call super.
+ MessageSend callToSuper = new MessageSend();
+ callToSuper.receiver = new SuperReference(0, 0);
+ callToSuper.selector = FILL_VALUES_METHOD_NAME;
+ callToSuper.arguments = new Expression[] {new SingleNameReference(INSTANCE_VARIABLE_NAME, 0)};
+ body.add(callToSuper);
+ }
+
+ // Call the builder implemention's helper method that actually fills the values from the instance.
+ MessageSend callStaticFillValuesMethod = new MessageSend();
+ callStaticFillValuesMethod.receiver = new SingleNameReference(builderClassName.toCharArray(), 0);
+ callStaticFillValuesMethod.selector = FILL_VALUES_STATIC_METHOD_NAME;
+ callStaticFillValuesMethod.arguments = new Expression[] {new SingleNameReference(INSTANCE_VARIABLE_NAME, 0), new ThisReference(0, 0)};
+ body.add(callStaticFillValuesMethod);
+
+ // Return self().
+ MessageSend returnCall = new MessageSend();
+ returnCall.receiver = ThisReference.implicitThis();
+ returnCall.selector = SELF_METHOD_NAME;
+ body.add(new ReturnStatement(returnCall, 0, 0));
+
+ out.statements = body.isEmpty() ? null : body.toArray(new Statement[body.size()]);
+
+ return out;
+ }
+
+ /**
+ * Generates a <code>$fillValuesFromInstanceIntoBuilder()</code> method in
+ * the builder implementation class that copies all fields from the instance
+ * to the builder. It looks like this:
+ *
+ * <pre>
+ * protected B $fillValuesFromInstanceIntoBuilder(Foobar instance, FoobarBuilder&lt;?, ?&gt; b) {
+ * b.field(instance.field);
+ * }
+ * </pre>
+ */
+ private MethodDeclaration generateStaticFillValuesMethod(EclipseNode tdParent, String builderClassName, TypeParameter[] typeParams, java.util.List<BuilderFieldData> builderFields, ASTNode source) {
+ MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult);
+ out.selector = FILL_VALUES_STATIC_METHOD_NAME;
+ out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
+ out.modifiers = ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic;
+ out.returnType = TypeReference.baseTypeReference(TypeIds.T_void, 0);
+
+ TypeReference[] wildcards = new TypeReference[] {new Wildcard(Wildcard.UNBOUND), new Wildcard(Wildcard.UNBOUND)};
+ TypeReference builderType = new ParameterizedSingleTypeReference(builderClassName.toCharArray(), mergeToTypeReferences(typeParams, wildcards), 0, 0);
+ Argument builderArgument = new Argument(BUILDER_VARIABLE_NAME, 0, builderType, Modifier.FINAL);
+ TypeReference parentArgument = createTypeReferenceWithTypeParameters(tdParent.getName(), typeParams);
+ out.arguments = new Argument[] {new Argument(INSTANCE_VARIABLE_NAME, 0, parentArgument, Modifier.FINAL), builderArgument};
+
+ // Add type params if there are any.
+ if (typeParams.length > 0) out.typeParameters = copyTypeParams(typeParams, source);
+
+ List<Statement> body = new ArrayList<Statement>();
+
+ // Call the builder's setter methods to fill the values from the instance.
+ for (BuilderFieldData bfd : builderFields) {
+ MessageSend exec = createSetterCallWithInstanceValue(bfd, tdParent, source);
+ body.add(exec);
+ }
+
+ out.statements = body.isEmpty() ? null : body.toArray(new Statement[body.size()]);
+
+ return out;
+ }
+
+ private MessageSend createSetterCallWithInstanceValue(BuilderFieldData bfd, EclipseNode type, ASTNode source) {
+ char[] setterName = bfd.name;
+ MessageSend ms = new MessageSend();
+ Expression[] tgt = new Expression[bfd.singularData == null ? 1 : 2];
+
+ if (bfd.obtainVia == null || !bfd.obtainVia.field().isEmpty()) {
+ char[] fieldName = bfd.obtainVia == null ? bfd.rawName : bfd.obtainVia.field().toCharArray();
+ for (int i = 0; i < tgt.length; i++) {
+ FieldReference fr = new FieldReference(fieldName, 0);
+ fr.receiver = new SingleNameReference(INSTANCE_VARIABLE_NAME, 0);
+ tgt[i] = fr;
+ }
+ } else {
+ String obtainName = bfd.obtainVia.method();
+ boolean obtainIsStatic = bfd.obtainVia.isStatic();
+ for (int i = 0; i < tgt.length; i++) {
+ MessageSend obtainExpr = new MessageSend();
+ obtainExpr.receiver = obtainIsStatic ? new SingleNameReference(type.getName().toCharArray(), 0) : new SingleNameReference(INSTANCE_VARIABLE_NAME, 0);
+ obtainExpr.selector = obtainName.toCharArray();
+ if (obtainIsStatic) obtainExpr.arguments = new Expression[] {new SingleNameReference(INSTANCE_VARIABLE_NAME, 0)};
+ tgt[i] = obtainExpr;
+ }
+ }
+ if (bfd.singularData == null) {
+ ms.arguments = tgt;
+ } else {
+ Expression ifNull = new EqualExpression(tgt[0], new NullLiteral(0, 0), OperatorIds.EQUAL_EQUAL);
+ MessageSend emptyList = new MessageSend();
+ emptyList.receiver = generateQualifiedNameRef(source, TypeConstants.JAVA, TypeConstants.UTIL, "Collections".toCharArray());
+ emptyList.selector = EMPTY_LIST;
+ ms.arguments = new Expression[] {new ConditionalExpression(ifNull, emptyList, tgt[1])};
+ }
+ ms.receiver = new SingleNameReference(BUILDER_VARIABLE_NAME, 0);
+ ms.selector = setterName;
+ return ms;
+ }
+
private MethodDeclaration generateAbstractSelfMethod(EclipseNode tdParent, boolean override, String builderGenericName) {
MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult);
out.selector = SELF_METHOD_NAME;
diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java
index 17fc5e09..4b094a9f 100644
--- a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java
+++ b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java
@@ -94,6 +94,7 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer {
buildField.modifiers = ClassFileConstants.AccPrivate;
buildField.declarationSourceEnd = -1;
buildField.type = type;
+
data.setGeneratedByRecursive(buildField);
return Collections.singletonList(injectFieldAndMarkGenerated(builderType, buildField));
}
@@ -117,6 +118,7 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer {
md.returnType = returnType;
md.annotations = deprecate ? new Annotation[] { generateDeprecatedAnnotation(data.getSource()) } : null;
+ data.setGeneratedByRecursive(md);
injectMethod(builderType, md);
}
diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java
index c7315790..11314bd3 100644
--- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java
+++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java
@@ -85,6 +85,7 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula
buildField.modifiers = ClassFileConstants.AccPrivate;
buildField.declarationSourceEnd = -1;
buildField.type = type;
+
data.setGeneratedByRecursive(buildField);
return Collections.singletonList(injectFieldAndMarkGenerated(builderType, buildField));
}
@@ -117,6 +118,8 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula
md.statements = returnStatement != null ? new Statement[] {clearStatement, returnStatement} : new Statement[] {clearStatement};
md.returnType = returnType;
md.annotations = deprecate ? new Annotation[] { generateDeprecatedAnnotation(data.getSource()) } : null;
+
+ data.setGeneratedByRecursive(md);
injectMethod(builderType, md);
}
@@ -149,7 +152,6 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula
md.annotations = deprecate ? new Annotation[] { generateDeprecatedAnnotation(data.getSource()) } : null;
data.setGeneratedByRecursive(md);
-
HandleNonNull.INSTANCE.fix(injectMethod(builderType, md));
}
diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java
index 174cd5fc..55f6cadd 100644
--- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java
+++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java
@@ -127,6 +127,7 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer
buildValueField.declarationSourceEnd = -1;
buildValueField.type = type;
}
+
data.setGeneratedByRecursive(buildKeyField);
data.setGeneratedByRecursive(buildValueField);
EclipseNode keyFieldNode = injectFieldAndMarkGenerated(builderType, buildKeyField);
@@ -174,6 +175,7 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer
md.returnType = returnType;
md.annotations = deprecate ? new Annotation[] { generateDeprecatedAnnotation(data.getSource()) } : null;
+ data.setGeneratedByRecursive(md);
injectMethod(builderType, md);
}
diff --git a/src/core/lombok/experimental/SuperBuilder.java b/src/core/lombok/experimental/SuperBuilder.java
index 26127a5f..be6ea304 100644
--- a/src/core/lombok/experimental/SuperBuilder.java
+++ b/src/core/lombok/experimental/SuperBuilder.java
@@ -1,16 +1,16 @@
/*
* Copyright (C) 2018 The Project Lombok Authors.
- *
+ *
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
- *
+ *
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -43,7 +43,7 @@ import lombok.Singular;
* The builder also has a <code>build()</code> method which returns a completed instance of the original type.
* <p>
* Complete documentation is found at <a href="https://projectlombok.org/features/experimental/SuperBuilder">the project lombok features page for &#64;SuperBuilder</a>.
- *
+ *
* @see Singular
*/
@Target(TYPE)
@@ -51,16 +51,15 @@ import lombok.Singular;
public @interface SuperBuilder {
/** @return Name of the method that creates a new builder instance. Default: {@code builder}. */
String builderMethodName() default "builder";
-
+
/** @return Name of the method in the builder class that creates an instance of your {@code @Builder}-annotated class. */
String buildMethodName() default "build";
-
- // toBuilder also requires a two-stage system where each class gets its own toBuilder but calls on a second method (and also calls parentclass's method)
- // to fill the builder, as this class does not know what fields to pass on to the builder. Let's consider this, but only for milestone 2.
- /*
- * If true, generate an instance method to obtain a builder that is initialized with the values of this instance.
- *
+
+ /**
+ * If <code>true</code>, generate an instance method to obtain a builder that is initialized with the values of this instance.
+ * In this case, all superclasses must also have <code>toBuilder=true</code>.
+ *
* @return Whether to generate a {@code toBuilder()} method.
*/
-// boolean toBuilder() default false;
+ boolean toBuilder() default false;
}
diff --git a/src/core/lombok/javac/CompilerMessageSuppressor.java b/src/core/lombok/javac/CompilerMessageSuppressor.java
index 391ec64a..02dc6c26 100644
--- a/src/core/lombok/javac/CompilerMessageSuppressor.java
+++ b/src/core/lombok/javac/CompilerMessageSuppressor.java
@@ -39,6 +39,8 @@ import com.sun.tools.javac.util.JCDiagnostic;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Log;
+import lombok.permit.Permit;
+
/**
* During resolution, the resolver will emit resolution errors, but without appropriate file names and line numbers. If these resolution errors stick around
* then they will be generated AGAIN, this time with proper names and line numbers, at the end. Therefore, we want to suppress the logger.
@@ -89,11 +91,8 @@ public final class CompilerMessageSuppressor {
static Field getDeclaredField(Class<?> c, String fieldName) {
try {
- Field field = c.getDeclaredField(fieldName);
- field.setAccessible(true);
- return field;
- }
- catch (Throwable t) {
+ return Permit.getField(c, fieldName);
+ } catch (Throwable t) {
return null;
}
}
diff --git a/src/core/lombok/javac/Javac6BasedLombokOptions.java b/src/core/lombok/javac/Javac6BasedLombokOptions.java
index cefb89ff..fc73181c 100644
--- a/src/core/lombok/javac/Javac6BasedLombokOptions.java
+++ b/src/core/lombok/javac/Javac6BasedLombokOptions.java
@@ -25,6 +25,7 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import lombok.Lombok;
+import lombok.permit.Permit;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Options;
@@ -36,8 +37,8 @@ public class Javac6BasedLombokOptions extends LombokOptions {
static {
try {
Class<?> optionNameClass = Class.forName("com.sun.tools.javac.main.OptionName");
- optionName_valueOf = optionNameClass.getMethod("valueOf", String.class);
- options_put = Class.forName("com.sun.tools.javac.util.Options").getMethod("put", optionNameClass, String.class);
+ optionName_valueOf = Permit.getMethod(optionNameClass, "valueOf", String.class);
+ options_put = Permit.getMethod(Class.forName("com.sun.tools.javac.util.Options"), "put", optionNameClass, String.class);
} catch (Exception e) {
throw new IllegalArgumentException("Can't initialize Javac6-based lombok options due to reflection issue.", e);
}
diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java
index 091612cc..9a5305a6 100644
--- a/src/core/lombok/javac/JavacAST.java
+++ b/src/core/lombok/javac/JavacAST.java
@@ -37,6 +37,7 @@ import javax.tools.JavaFileObject;
import com.sun.tools.javac.util.JCDiagnostic;
import lombok.core.AST;
+import lombok.permit.Permit;
import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.code.Symtab;
@@ -243,7 +244,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
private static List<JCTree> getResourcesForTryNode(JCTry tryNode) {
if (!JCTRY_RESOURCES_FIELD_INITIALIZED) {
try {
- JCTRY_RESOURCES_FIELD = JCTry.class.getField("resources");
+ JCTRY_RESOURCES_FIELD = Permit.getField(JCTry.class, "resources");
} catch (NoSuchFieldException ignore) {
// Java 1.6 or lower won't have this at all.
} catch (Exception ignore) {
@@ -343,7 +344,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
return m;
}
try {
- m = c.getMethod("getBody");
+ m = Permit.getMethod(c, "getBody");
} catch (NoSuchMethodException e) {
throw Javac.sneakyThrow(e);
}
@@ -501,12 +502,11 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
}
static ErrorLog create(Messager messager, Log log) {
- Field errorCount = null;
- try {
- Field f = messager.getClass().getDeclaredField("errorCount");
- f.setAccessible(true);
- errorCount = f;
- } catch (Throwable t) {}
+ Field errorCount; try {
+ errorCount = Permit.getField(messager.getClass(), "errorCount");
+ } catch (Throwable t) {
+ errorCount = null;
+ }
boolean hasMultipleErrors = false;
for (Field field : log.getClass().getFields()) {
if (field.getName().equals("multipleErrors")) {
@@ -515,14 +515,13 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
}
}
if (hasMultipleErrors) return new JdkBefore9(log, messager, errorCount);
-
- Field warningCount = null;
- try {
- Field f = messager.getClass().getDeclaredField("warningCount");
- f.setAccessible(true);
- warningCount = f;
- } catch (Throwable t) {}
-
+
+ Field warningCount; try {
+ warningCount = Permit.getField(messager.getClass(), "warningCount");
+ } catch (Throwable t) {
+ warningCount = null;
+ }
+
return new Jdk9Plus(log, messager, errorCount, warningCount);
}
}
@@ -577,21 +576,18 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> {
Class<?> noteCls = Class.forName(jcd + "$Note");
Class<?> lc = log.getClass();
- this.errorMethod = lc.getMethod("error", df, DiagnosticPosition.class, errorCls);
- this.warningMethod = lc.getMethod("warning", DiagnosticPosition.class, warningCls);
- this.mandatoryWarningMethod = lc.getMethod("mandatoryWarning", DiagnosticPosition.class, warningCls);
- this.noteMethod = lc.getMethod("note", DiagnosticPosition.class, noteCls);
+ this.errorMethod = Permit.getMethod(lc, "error", df, DiagnosticPosition.class, errorCls);
+ this.warningMethod = Permit.getMethod(lc, "warning", DiagnosticPosition.class, warningCls);
+ this.mandatoryWarningMethod = Permit.getMethod(lc, "mandatoryWarning", DiagnosticPosition.class, warningCls);
+ this.noteMethod = Permit.getMethod(lc, "note", DiagnosticPosition.class, noteCls);
- Field diagsField = lc.getSuperclass().getDeclaredField("diags");
- diagsField.setAccessible(true);
- this.diags = (JCDiagnostic.Factory)diagsField.get(log);
+ Field diagsField = Permit.getField(lc.getSuperclass(), "diags");
+ this.diags = (JCDiagnostic.Factory) diagsField.get(log);
Class<?> dc = this.diags.getClass();
- this.errorKey = dc.getMethod("errorKey", String.class, Object[].class);
- this.warningKey = dc.getDeclaredMethod("warningKey", String.class, Object[].class);
- this.warningKey.setAccessible(true);
- this.noteKey = dc.getDeclaredMethod("noteKey", String.class, Object[].class);
- this.noteKey.setAccessible(true);
+ this.errorKey = Permit.getMethod(dc, "errorKey", String.class, Object[].class);
+ this.warningKey = Permit.getMethod(dc, "warningKey", String.class, Object[].class);
+ this.noteKey = Permit.getMethod(dc, "noteKey", String.class, Object[].class);
} catch (Throwable t) {
//t.printStackTrace();
}
diff --git a/src/core/lombok/javac/JavacResolution.java b/src/core/lombok/javac/JavacResolution.java
index 8cc239e1..abbf6726 100644
--- a/src/core/lombok/javac/JavacResolution.java
+++ b/src/core/lombok/javac/JavacResolution.java
@@ -35,6 +35,7 @@ import javax.tools.JavaFileObject;
import lombok.Lombok;
import lombok.core.debug.AssertionLogger;
+import lombok.permit.Permit;
import com.sun.tools.javac.code.BoundKind;
import com.sun.tools.javac.code.Symbol.TypeSymbol;
@@ -162,14 +163,10 @@ public class JavacResolution {
private static Field getMemberEnterDotEnv() {
if (memberEnterDotEnv != null) return memberEnterDotEnv;
try {
- Field f = MemberEnter.class.getDeclaredField("env");
- f.setAccessible(true);
- memberEnterDotEnv = f;
+ return memberEnterDotEnv = Permit.getField(MemberEnter.class, "env");
} catch (NoSuchFieldException e) {
return null;
}
-
- return memberEnterDotEnv;
}
@SuppressWarnings("unchecked")
@@ -252,10 +249,10 @@ public class JavacResolution {
static {
Method upperBound = null;
try {
- upperBound = Types.class.getMethod("upperBound", Type.class);
+ upperBound = Permit.getMethod(Types.class, "upperBound", Type.class);
} catch (Throwable ignore) {}
if (upperBound == null) try {
- upperBound = Types.class.getMethod("wildUpperBound", Type.class);
+ upperBound = Permit.getMethod(Types.class, "wildUpperBound", Type.class);
} catch (Throwable ignore) {}
UPPER_BOUND = upperBound;
diff --git a/src/core/lombok/javac/apt/LombokFileObjects.java b/src/core/lombok/javac/apt/LombokFileObjects.java
index aba10540..28d3c9fa 100644
--- a/src/core/lombok/javac/apt/LombokFileObjects.java
+++ b/src/core/lombok/javac/apt/LombokFileObjects.java
@@ -39,6 +39,7 @@ import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import lombok.core.DiagnosticsReceiver;
+import lombok.permit.Permit;
import com.sun.tools.javac.file.BaseFileManager;
@@ -87,16 +88,14 @@ final class LombokFileObjects {
}
static Method getDecoderMethod(String className) {
- Method m = null;
try {
- m = Class.forName(className).getDeclaredMethod("getDecoder", boolean.class);
- m.setAccessible(true);
+ return Permit.getMethod(Class.forName(className), "getDecoder", boolean.class);
} catch (NoSuchMethodException e) {
// Intentional fallthrough - getDecoder(boolean) is not always present.
} catch (ClassNotFoundException e) {
// Intentional fallthrough - getDecoder(boolean) is not always present.
}
- return m;
+ return null;
}
private LombokFileObjects() {}
diff --git a/src/core/lombok/javac/apt/LombokProcessor.java b/src/core/lombok/javac/apt/LombokProcessor.java
index 247d0560..a3d1dfcf 100644
--- a/src/core/lombok/javac/apt/LombokProcessor.java
+++ b/src/core/lombok/javac/apt/LombokProcessor.java
@@ -52,6 +52,7 @@ import javax.tools.JavaFileObject;
import lombok.Lombok;
import lombok.core.DiagnosticsReceiver;
import lombok.javac.JavacTransformer;
+import lombok.permit.Permit;
import com.sun.source.util.TreePath;
import com.sun.source.util.Trees;
@@ -112,10 +113,7 @@ public class LombokProcessor extends AbstractProcessor {
private static final Field getFieldAccessor(String typeName, String fieldName) {
try {
- Class<?> c = Class.forName(typeName);
- Field f = c.getDeclaredField(fieldName);
- f.setAccessible(true);
- return f;
+ return Permit.getField(Class.forName(typeName), fieldName);
} catch (ClassNotFoundException e) {
return null;
} catch (NoSuchFieldException e) {
@@ -156,11 +154,9 @@ public class LombokProcessor extends AbstractProcessor {
Context context = javacProcessingEnv.getContext();
disablePartialReparseInNetBeansEditor(context);
try {
- Method keyMethod = Context.class.getDeclaredMethod("key", Class.class);
- keyMethod.setAccessible(true);
+ Method keyMethod = Permit.getMethod(Context.class, "key", Class.class);
Object key = keyMethod.invoke(context, JavaFileManager.class);
- Field htField = Context.class.getDeclaredField("ht");
- htField.setAccessible(true);
+ Field htField = Permit.getField(Context.class, "ht");
@SuppressWarnings("unchecked")
Map<Object,Object> ht = (Map<Object,Object>) htField.get(context);
final JavaFileManager originalFiler = (JavaFileManager) ht.get(key);
@@ -170,8 +166,7 @@ public class LombokProcessor extends AbstractProcessor {
JavaFileManager newFilerManager = new InterceptingJavaFileManager(originalFiler, receiver);
ht.put(key, newFilerManager);
- Field filerFileManagerField = JavacFiler.class.getDeclaredField("fileManager");
- filerFileManagerField.setAccessible(true);
+ Field filerFileManagerField = Permit.getField(JavacFiler.class, "fileManager");
filerFileManagerField.set(javacFiler, newFilerManager);
if (lombok.javac.Javac.getJavaCompilerVersion() > 8
@@ -186,20 +181,17 @@ public class LombokProcessor extends AbstractProcessor {
private void replaceFileManagerJdk9(Context context, JavaFileManager newFiler) {
try {
- JavaCompiler compiler = (JavaCompiler) JavaCompiler.class.getDeclaredMethod("instance", Context.class).invoke(null, context);
+ JavaCompiler compiler = (JavaCompiler) Permit.getMethod(JavaCompiler.class, "instance", Context.class).invoke(null, context);
try {
- Field fileManagerField = JavaCompiler.class.getDeclaredField("fileManager");
- fileManagerField.setAccessible(true);
+ Field fileManagerField = Permit.getField(JavaCompiler.class, "fileManager");
fileManagerField.set(compiler, newFiler);
}
catch (Exception e) {}
try {
- Field writerField = JavaCompiler.class.getDeclaredField("writer");
- writerField.setAccessible(true);
+ Field writerField = Permit.getField(JavaCompiler.class, "writer");
ClassWriter writer = (ClassWriter) writerField.get(compiler);
- Field fileManagerField = ClassWriter.class.getDeclaredField("fileManager");
- fileManagerField.setAccessible(true);
+ Field fileManagerField = Permit.getField(ClassWriter.class, "fileManager");
fileManagerField.set(writer, newFiler);
}
catch (Exception e) {}
@@ -210,8 +202,7 @@ public class LombokProcessor extends AbstractProcessor {
private void forceMultipleRoundsInNetBeansEditor() {
try {
- Field f = JavacProcessingEnvironment.class.getDeclaredField("isBackgroundCompilation");
- f.setAccessible(true);
+ Field f = Permit.getField(JavacProcessingEnvironment.class, "isBackgroundCompilation");
f.set(javacProcessingEnv, true);
} catch (NoSuchFieldException e) {
// only NetBeans has it
@@ -223,14 +214,12 @@ public class LombokProcessor extends AbstractProcessor {
private void disablePartialReparseInNetBeansEditor(Context context) {
try {
Class<?> cancelServiceClass = Class.forName("com.sun.tools.javac.util.CancelService");
- Method cancelServiceInstace = cancelServiceClass.getDeclaredMethod("instance", Context.class);
+ Method cancelServiceInstace = Permit.getMethod(cancelServiceClass, "instance", Context.class);
Object cancelService = cancelServiceInstace.invoke(null, context);
if (cancelService == null) return;
- Field parserField = cancelService.getClass().getDeclaredField("parser");
- parserField.setAccessible(true);
+ Field parserField = Permit.getField(cancelService.getClass(), "parser");
Object parser = parserField.get(cancelService);
- Field supportsReparseField = parser.getClass().getDeclaredField("supportsReparse");
- supportsReparseField.setAccessible(true);
+ Field supportsReparseField = Permit.getField(parser.getClass(), "supportsReparse");
supportsReparseField.set(parser, false);
} catch (ClassNotFoundException e) {
// only NetBeans has it
@@ -284,8 +273,7 @@ public class LombokProcessor extends AbstractProcessor {
private void stopJavacProcessingEnvironmentFromClosingOurClassloader() {
try {
- Field f = JavacProcessingEnvironment.class.getDeclaredField("processorClassLoader");
- f.setAccessible(true);
+ Field f = Permit.getField(JavacProcessingEnvironment.class, "processorClassLoader");
ClassLoader unwrapped = (ClassLoader) f.get(javacProcessingEnv);
if (unwrapped == null) return;
ClassLoader wrapped = wrapClassLoader(unwrapped);
@@ -377,7 +365,7 @@ public class LombokProcessor extends AbstractProcessor {
} catch (Exception e) {
e.printStackTrace();
processingEnv.getMessager().printMessage(Kind.WARNING,
- "Can't force a new processing round. Lombok won't work.");
+ "Can't force a new processing round. Lombok won't work.");
}
}
}
@@ -414,16 +402,14 @@ public class LombokProcessor extends AbstractProcessor {
@Override public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
-
+
/**
* This class casts the given processing environment to a JavacProcessingEnvironment. In case of
* gradle incremental compilation, the delegate ProcessingEnvironment of the gradle wrapper is returned.
*/
public JavacProcessingEnvironment getJavacProcessingEnvironment(Object procEnv) {
- if (procEnv instanceof JavacProcessingEnvironment) {
- return (JavacProcessingEnvironment) procEnv;
- }
-
+ if (procEnv instanceof JavacProcessingEnvironment) return (JavacProcessingEnvironment) procEnv;
+
// try to find a "delegate" field in the object, and use this to try to obtain a JavacProcessingEnvironment
for (Class<?> procEnvClass = procEnv.getClass(); procEnvClass != null; procEnvClass = procEnvClass.getSuperclass()) {
try {
@@ -432,9 +418,9 @@ public class LombokProcessor extends AbstractProcessor {
// delegate field was not found, try on superclass
}
}
-
+
processingEnv.getMessager().printMessage(Kind.WARNING,
- "Can't get the delegate of the gradle IncrementalProcessingEnvironment. Lombok won't work.");
+ "Can't get the delegate of the gradle IncrementalProcessingEnvironment. Lombok won't work.");
return null;
}
@@ -444,10 +430,8 @@ public class LombokProcessor extends AbstractProcessor {
* (directly or through a delegate field again)
*/
public JavacFiler getJavacFiler(Object filer) {
- if (filer instanceof JavacFiler) {
- return (JavacFiler) filer;
- }
-
+ if (filer instanceof JavacFiler) return (JavacFiler) filer;
+
// try to find a "delegate" field in the object, and use this to check for a JavacFiler
for (Class<?> filerClass = filer.getClass(); filerClass != null; filerClass = filerClass.getSuperclass()) {
try {
@@ -456,15 +440,13 @@ public class LombokProcessor extends AbstractProcessor {
// delegate field was not found, try on superclass
}
}
-
+
processingEnv.getMessager().printMessage(Kind.WARNING,
- "Can't get a JavacFiler from " + filer.getClass().getName() + ". Lombok won't work.");
+ "Can't get a JavacFiler from " + filer.getClass().getName() + ". Lombok won't work.");
return null;
}
private Object tryGetDelegateField(Class<?> delegateClass, Object instance) throws Exception {
- Field field = delegateClass.getDeclaredField("delegate");
- field.setAccessible(true);
- return field.get(instance);
+ return Permit.getField(delegateClass, "delegate").get(instance);
}
}
diff --git a/src/core/lombok/javac/apt/Processor.java b/src/core/lombok/javac/apt/Processor.java
index 7a187148..f15bf74c 100644
--- a/src/core/lombok/javac/apt/Processor.java
+++ b/src/core/lombok/javac/apt/Processor.java
@@ -53,6 +53,8 @@ import com.sun.tools.javac.processing.JavacFiler;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.util.Options;
+import lombok.permit.Permit;
+
/**
* This processor should not be used. It used to be THE processor. This class is only there to warn people that something went wrong, and for the
* lombok developers to see if what the reason for those failures is.
@@ -101,8 +103,7 @@ public class Processor extends AbstractProcessor {
try {
JavacProcessingEnvironment environment = (JavacProcessingEnvironment) procEnv;
Options instance = Options.instance(environment.getContext());
- Field field = Options.class.getDeclaredField("values");
- field.setAccessible(true);
+ Field field = Permit.getField(Options.class, "values");
@SuppressWarnings("unchecked") Map<String, String> values = (Map<String, String>) field.get(instance);
if (values.isEmpty()) {
message.append("Options: empty\n\n");
@@ -125,8 +126,7 @@ public class Processor extends AbstractProcessor {
private void findServices(StringBuilder message, Filer filer) {
try {
- Field filerFileManagerField = JavacFiler.class.getDeclaredField("fileManager");
- filerFileManagerField.setAccessible(true);
+ Field filerFileManagerField = Permit.getField(JavacFiler.class, "fileManager");
JavaFileManager jfm = (JavaFileManager) filerFileManagerField.get(filer);
ClassLoader processorClassLoader = jfm.hasLocation(ANNOTATION_PROCESSOR_PATH) ? jfm.getClassLoader(ANNOTATION_PROCESSOR_PATH) : jfm.getClassLoader(CLASS_PATH);
Enumeration<URL> resources = processorClassLoader.getResources("META-INF/services/javax.annotation.processing.Processor");
diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java
index 903844d2..0f6e21d0 100644
--- a/src/core/lombok/javac/handlers/HandleBuilder.java
+++ b/src/core/lombok/javac/handlers/HandleBuilder.java
@@ -84,7 +84,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
return ((Boolean) expr).booleanValue();
}
- private static class BuilderFieldData {
+ static class BuilderFieldData {
List<JCAnnotation> annotations;
JCExpression type;
Name rawName;
@@ -484,6 +484,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
sb.append("__ERR__");
}
+ private static final String BUILDER_TEMP_VAR = "builder";
private JCMethodDecl generateToBuilderMethod(String toBuilderMethodName, String builderClassName, JavacNode type, List<JCTypeParameter> typeParams, java.util.List<BuilderFieldData> builderFields, boolean fluent, JCAnnotation ast) {
// return new ThingieBuilder<A, B>().setA(this.a).setB(this.b);
JavacTreeMaker maker = type.getTreeMaker();
@@ -495,6 +496,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
JCExpression call = maker.NewClass(null, List.<JCExpression>nil(), namePlusTypeParamsToTypeReference(maker, type.toName(builderClassName), typeParams), List.<JCExpression>nil(), null);
JCExpression invoke = call;
+ ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();
for (BuilderFieldData bfd : builderFields) {
Name setterName = fluent ? bfd.name : type.toName(HandlerUtil.buildAccessorName("set", bfd.name.toString()));
JCExpression[] tgt = new JCExpression[bfd.singularData == null ? 1 : 2];
@@ -519,19 +521,21 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
JCExpression arg;
if (bfd.singularData == null) {
arg = tgt[0];
+ invoke = maker.Apply(List.<JCExpression>nil(), maker.Select(invoke, setterName), List.of(arg));
} else {
- JCExpression eqNull = maker.Binary(CTC_EQUAL, tgt[0], maker.Literal(CTC_BOT, null));
- // Use the singularizer to create the type args (will remove possible wildcards on the type).
- List<JCExpression> tas = bfd.singularData.getSingularizer().createTypeArgs(bfd.singularData.getTypeArgs().size(), false, type, bfd.singularData.getTypeArgs(), type.get());
- JCExpression emptyList = maker.Apply(tas, chainDots(type, "java", "util", "Collections", "emptyList"), List.<JCExpression>nil());
- arg = maker.Conditional(eqNull, emptyList, tgt[1]);
+ JCExpression isNotNull = maker.Binary(CTC_NOT_EQUAL, tgt[0], maker.Literal(CTC_BOT, null));
+ JCExpression invokeBuilder = maker.Apply(List.<JCExpression>nil(), maker.Select(maker.Ident(type.toName(BUILDER_TEMP_VAR)), setterName), List.<JCExpression>of(tgt[1]));
+ statements.append(maker.If(isNotNull, maker.Exec(invokeBuilder), null));
}
-
- invoke = maker.Apply(List.<JCExpression>nil(), maker.Select(invoke, setterName), List.of(arg));
}
- JCStatement statement = maker.Return(invoke);
-
- JCBlock body = maker.Block(0, List.<JCStatement>of(statement));
+ if (!statements.isEmpty()) {
+ JCExpression tempVarType = namePlusTypeParamsToTypeReference(maker, type.toName(builderClassName), typeParams);
+ statements.prepend(maker.VarDef(maker.Modifiers(Flags.FINAL), type.toName(BUILDER_TEMP_VAR), tempVarType, invoke));
+ statements.append(maker.Return(maker.Ident(type.toName(BUILDER_TEMP_VAR))));
+ } else {
+ statements.append(maker.Return(invoke));
+ }
+ JCBlock body = maker.Block(0, statements.toList());
return maker.MethodDef(maker.Modifiers(Flags.PUBLIC), type.toName(toBuilderMethodName), namePlusTypeParamsToTypeReference(maker, type.toName(builderClassName), typeParams), List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null);
}
diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java
index 66d6e47e..8af0a7c0 100644
--- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java
+++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java
@@ -27,6 +27,8 @@ import static lombok.javac.handlers.JavacHandlerUtil.*;
import java.util.ArrayList;
+import javax.lang.model.element.Modifier;
+
import org.mangosdk.spi.ProviderFor;
import com.sun.tools.javac.code.BoundKind;
@@ -37,11 +39,13 @@ import com.sun.tools.javac.tree.JCTree.JCAssign;
import com.sun.tools.javac.tree.JCTree.JCBlock;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
import com.sun.tools.javac.tree.JCTree.JCModifiers;
+import com.sun.tools.javac.tree.JCTree.JCReturn;
import com.sun.tools.javac.tree.JCTree.JCStatement;
import com.sun.tools.javac.tree.JCTree.JCTypeApply;
import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
@@ -61,6 +65,7 @@ import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.core.HandlerPriority;
import lombok.core.handlers.HandlerUtil;
+import lombok.core.handlers.HandlerUtil.FieldAccess;
import lombok.core.handlers.InclusionExclusionUtils.Included;
import lombok.experimental.NonFinal;
import lombok.experimental.SuperBuilder;
@@ -68,32 +73,23 @@ import lombok.javac.Javac;
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
import lombok.javac.JavacTreeMaker;
+import lombok.javac.handlers.HandleBuilder.BuilderFieldData;
import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult;
import lombok.javac.handlers.JavacSingularsRecipes.ExpressionMaker;
-import lombok.javac.handlers.JavacSingularsRecipes.StatementMaker;
import lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer;
import lombok.javac.handlers.JavacSingularsRecipes.SingularData;
+import lombok.javac.handlers.JavacSingularsRecipes.StatementMaker;
@ProviderFor(JavacAnnotationHandler.class)
@HandlerPriority(-1024) //-2^10; to ensure we've picked up @FieldDefault's changes (-2048) but @Value hasn't removed itself yet (-512), so that we can error on presence of it on the builder classes.
public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
private static final String SELF_METHOD = "self";
-
- private static class BuilderFieldData {
- List<JCAnnotation> annotations;
- JCExpression type;
- Name rawName;
- Name name;
- Name nameOfDefaultProvider;
- Name nameOfSetFlag;
- SingularData singularData;
- ObtainVia obtainVia;
- JavacNode obtainViaNode;
- JavacNode originalFieldNode;
-
- java.util.List<JavacNode> createdFields = new ArrayList<JavacNode>();
- }
-
+ private static final String TO_BUILDER_METHOD_NAME = "toBuilder";
+ private static final String FILL_VALUES_METHOD_NAME = "$fillValuesFrom";
+ private static final String STATIC_FILL_VALUES_METHOD_NAME = "$fillValuesFromInstanceIntoBuilder";
+ private static final String INSTANCE_VARIABLE_NAME = "instance";
+ private static final String BUILDER_VARIABLE_NAME = "b";
+
@Override
public void handle(AnnotationValues<SuperBuilder> annotation, JCAnnotation ast, JavacNode annotationNode) {
handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.SUPERBUILDER_FLAG_USAGE, "@SuperBuilder");
@@ -110,10 +106,11 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
if (!checkName("builderMethodName", builderMethodName, annotationNode)) return;
if (!checkName("buildMethodName", buildMethodName, annotationNode)) return;
+ boolean toBuilder = superbuilderAnnotation.toBuilder();
+
JavacNode tdParent = annotationNode.up();
java.util.List<BuilderFieldData> builderFields = new ArrayList<BuilderFieldData>();
- JCExpression returnType;
List<JCTypeParameter> typeParams = List.nil();
List<JCExpression> thrownExceptions = List.nil();
List<JCExpression> superclassTypeParams = List.nil();
@@ -192,7 +189,6 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
// If there is no superclass, superclassBuilderClassExpression is still == null at this point.
// You can use it to check whether to inherit or not.
- returnType = namePlusTypeParamsToTypeReference(tdParent.getTreeMaker(), td.name, td.typarams);
typeParams = td.typarams;
// <C, B> are the generics for our builder.
@@ -231,10 +227,25 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
JavacNode builderType = findInnerClass(tdParent, builderClassName);
if (builderType == null) {
builderType = generateBuilderAbstractClass(annotationNode, tdParent, builderClassName, superclassBuilderClassExpression,
- typeParams, superclassTypeParams, ast, classGenericName, builderGenericName);
+ typeParams, superclassTypeParams, classGenericName, builderGenericName);
} else {
- annotationNode.addError("@SuperBuilder does not support customized builders. Use @Builder instead.");
- return;
+ JCClassDecl builderTypeDeclaration = (JCClassDecl) builderType.get();
+ if (!builderTypeDeclaration.getModifiers().getFlags().contains(Modifier.STATIC)
+ || !builderTypeDeclaration.getModifiers().getFlags().contains(Modifier.ABSTRACT)) {
+ annotationNode.addError("Existing Builder must be an abstract static inner class.");
+ return;
+ }
+ sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderType, annotationNode);
+ // Generate errors for @Singular BFDs that have one already defined node.
+ for (BuilderFieldData bfd : builderFields) {
+ SingularData sd = bfd.singularData;
+ if (sd == null) continue;
+ JavacSingularizer singularizer = sd.getSingularizer();
+ if (singularizer == null) continue;
+ if (singularizer.checkForAlreadyExistingNodesAndGenerateError(builderType, sd)) {
+ bfd.singularData = null;
+ }
+ }
}
// Generate the fields in the abstract builder class that hold the values for the instance.
@@ -245,6 +256,13 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
injectFieldAndMarkGenerated(builderType, uncleanField);
}
+ if (toBuilder) {
+ // Generate $fillValuesFrom() method in the abstract builder.
+ injectMethod(builderType, generateFillValuesMethod(tdParent, superclassBuilderClassExpression != null, builderGenericName, classGenericName, builderClassName));
+ // Generate $fillValuesFromInstanceIntoBuilder() method in the builder implementation class.
+ injectMethod(builderType, generateStaticFillValuesMethod(tdParent, builderClassName, typeParams, builderFields));
+ }
+
// Generate abstract self() and build() methods in the abstract builder.
injectMethod(builderType, generateAbstractSelfMethod(tdParent, superclassBuilderClassExpression != null, builderGenericName));
injectMethod(builderType, generateAbstractBuildMethod(tdParent, buildMethodName, superclassBuilderClassExpression != null, classGenericName));
@@ -271,25 +289,33 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
recursiveSetGeneratedBy(builderType.get(), ast, annotationNode.getContext());
- if ((td.mods.flags & Flags.ABSTRACT) == 0) {
+ boolean isAbstract = (td.mods.flags & Flags.ABSTRACT) != 0;
+ if (!isAbstract) {
// Only non-abstract classes get the Builder implementation.
// Create the builder implementation class.
JavacNode builderImplType = findInnerClass(tdParent, builderImplClassName);
if (builderImplType == null) {
- builderImplType = generateBuilderImplClass(annotationNode, tdParent, builderImplClassName, builderClassName, typeParams, ast);
+ builderImplType = generateBuilderImplClass(annotationNode, tdParent, builderImplClassName, builderClassName, typeParams);
} else {
- annotationNode.addError("@SuperBuilder does not support customized builders. Use @Builder instead.");
- return;
+ JCClassDecl builderImplTypeDeclaration = (JCClassDecl) builderImplType.get();
+ if (!builderImplTypeDeclaration.getModifiers().getFlags().contains(Modifier.STATIC)
+ || builderImplTypeDeclaration.getModifiers().getFlags().contains(Modifier.ABSTRACT)) {
+ annotationNode.addError("Existing BuilderImpl must be a non-abstract static inner class.");
+ return;
+ }
+ sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderImplType, annotationNode);
}
-
+
// Create a simple constructor for the BuilderImpl class.
JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PRIVATE, List.<JCAnnotation>nil(), builderImplType, List.<JavacNode>nil(), false, annotationNode);
if (cd != null) injectMethod(builderImplType, cd);
// Create the self() and build() methods in the BuilderImpl.
injectMethod(builderImplType, generateSelfMethod(builderImplType, typeParams));
- injectMethod(builderImplType, generateBuildMethod(buildMethodName, returnType, builderImplType, thrownExceptions));
+ if (methodExists(buildMethodName, builderImplType, -1) == MemberExistsResult.NOT_EXISTS) {
+ injectMethod(builderImplType, generateBuildMethod(buildMethodName, tdParent, builderImplType, thrownExceptions));
+ }
recursiveSetGeneratedBy(builderImplType.get(), ast, annotationNode.getContext());
}
@@ -298,15 +324,32 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
generateBuilderBasedConstructor(tdParent, typeParams, builderFields, annotationNode, builderClassName,
superclassBuilderClassExpression != null);
- if ((td.mods.flags & Flags.ABSTRACT) == 0) {
- // Only non-abstract classes get the Builder implementation and the builder() method.
+ if (isAbstract) {
+ // Only non-abstract classes get the builder() and toBuilder() methods.
+ return;
+ }
- // 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) {
- JCMethodDecl builderMethod = generateBuilderMethod(builderMethodName, builderClassName, builderImplClassName, annotationNode, tdParent, typeParams);
- recursiveSetGeneratedBy(builderMethod, ast, annotationNode.getContext());
- if (builderMethod != null) injectMethod(tdParent, builderMethod);
+ // 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) {
+ JCMethodDecl builderMethod = generateBuilderMethod(builderMethodName, builderClassName, builderImplClassName, annotationNode, tdParent, typeParams);
+ recursiveSetGeneratedBy(builderMethod, ast, annotationNode.getContext());
+ if (builderMethod != null) injectMethod(tdParent, builderMethod);
+ }
+
+ // Add the toBuilder() method to the annotated class.
+ if (toBuilder) {
+ switch (methodExists(TO_BUILDER_METHOD_NAME, tdParent, 0)) {
+ case EXISTS_BY_USER:
+ annotationNode.addWarning("Not generating toBuilder() as it already exists.");
+ return;
+ case NOT_EXISTS:
+ JCMethodDecl md = generateToBuilderMethod(builderClassName, builderImplClassName, annotationNode, tdParent, typeParams);
+ if (md != null) {
+ injectMethod(tdParent, md);
+ }
+ default:
+ // Should not happen.
}
}
}
@@ -316,7 +359,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
*/
private JavacNode generateBuilderAbstractClass(JavacNode source, JavacNode tdParent, String builderClass,
JCExpression superclassBuilderClassExpression, List<JCTypeParameter> typeParams,
- List<JCExpression> superclassTypeParams, JCAnnotation ast, String classGenericName, String builderGenericName) {
+ List<JCExpression> superclassTypeParams, String classGenericName, String builderGenericName) {
JavacTreeMaker maker = tdParent.getTreeMaker();
JCModifiers mods = maker.Modifiers(Flags.STATIC | Flags.ABSTRACT | Flags.PUBLIC);
@@ -358,7 +401,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
/**
* Creates and returns the concrete builder implementation class and injects it into the annotated class.
*/
- private JavacNode generateBuilderImplClass(JavacNode source, JavacNode tdParent, String builderImplClass, String builderAbstractClass, List<JCTypeParameter> typeParams, JCAnnotation ast) {
+ private JavacNode generateBuilderImplClass(JavacNode source, JavacNode tdParent, String builderImplClass, String builderAbstractClass, List<JCTypeParameter> typeParams) {
JavacTreeMaker maker = tdParent.getTreeMaker();
JCModifiers mods = maker.Modifiers(Flags.STATIC | Flags.PRIVATE | Flags.FINAL);
@@ -410,7 +453,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();
- Name builderVariableName = typeNode.toName("b");
+ Name builderVariableName = typeNode.toName(BUILDER_VARIABLE_NAME);
for (BuilderFieldData bfd : builderFields) {
JCExpression rhs;
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
@@ -496,6 +539,166 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
return maker.MethodDef(maker.Modifiers(modifiers), type.toName(builderMethodName), returnType, copyTypeParams(source, typeParams), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null);
}
+ /**
+ * Generates a <code>toBuilder()</code> method in the annotated class that looks like this:
+ * <pre>
+ * public ParentBuilder&lt;?, ?&gt; toBuilder() {
+ * return new <i>Foobar</i>BuilderImpl().$fillValuesFrom(this);
+ * }
+ * </pre>
+ */
+ private JCMethodDecl generateToBuilderMethod(String builderClassName, String builderImplClassName, JavacNode source, JavacNode type, List<JCTypeParameter> typeParams) {
+ JavacTreeMaker maker = type.getTreeMaker();
+
+ ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>();
+ for (JCTypeParameter typeParam : typeParams) typeArgs.append(maker.Ident(typeParam.name));
+
+ JCExpression newClass = maker.NewClass(null, List.<JCExpression>nil(), namePlusTypeParamsToTypeReference(maker, type.toName(builderImplClassName), typeParams), List.<JCExpression>nil(), null);
+ List<JCExpression> methodArgs = List.<JCExpression>of(maker.Ident(type.toName("this")));
+ JCMethodInvocation invokeFillMethod = maker.Apply(List.<JCExpression>nil(), maker.Select(newClass, type.toName(FILL_VALUES_METHOD_NAME)), methodArgs);
+ JCStatement statement = maker.Return(invokeFillMethod);
+
+ JCBlock body = maker.Block(0, List.<JCStatement>of(statement));
+ int modifiers = Flags.PUBLIC;
+
+ // Add any type params of the annotated class to the return type.
+ ListBuffer<JCExpression> typeParameterNames = new ListBuffer<JCExpression>();
+ typeParameterNames.addAll(typeParameterNames(maker, typeParams));
+ // Now add the <?, ?>.
+ JCWildcard wildcard = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null);
+ typeParameterNames.add(wildcard);
+ typeParameterNames.add(wildcard);
+ JCTypeApply returnType = maker.TypeApply(maker.Ident(type.toName(builderClassName)), typeParameterNames.toList());
+
+ return maker.MethodDef(maker.Modifiers(modifiers), type.toName(TO_BUILDER_METHOD_NAME), returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null);
+ }
+
+ /**
+ * Generates a <code>$fillValuesFrom()</code> method in the abstract builder class that looks
+ * like this:
+ * <pre>
+ * protected B $fillValuesFrom(final C instance) {
+ * super.$fillValuesFrom(instance);
+ * FoobarBuilderImpl.$fillValuesFromInstanceIntoBuilder(instance, this);
+ * return self();
+ * }
+ * </pre>
+ */
+ private JCMethodDecl generateFillValuesMethod(JavacNode type, boolean inherited, String builderGenericName, String classGenericName, String builderImplClassName) {
+ JavacTreeMaker maker = type.getTreeMaker();
+ List<JCAnnotation> annotations = List.nil();
+ if (inherited) {
+ JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(type, "Override"), List.<JCExpression>nil());
+ annotations = List.of(overrideAnnotation);
+ }
+ JCModifiers modifiers = maker.Modifiers(Flags.PROTECTED, annotations);
+ Name name = type.toName(FILL_VALUES_METHOD_NAME);
+ JCExpression returnType = maker.Ident(type.toName(builderGenericName));
+
+ JCExpression classGenericNameExpr = maker.Ident(type.toName(classGenericName));
+ JCVariableDecl param = maker.VarDef(maker.Modifiers(Flags.LocalVarFlags), type.toName(INSTANCE_VARIABLE_NAME), classGenericNameExpr, null);
+
+ ListBuffer<JCStatement> body = new ListBuffer<JCStatement>();
+
+ if (inherited) {
+ // Call super.
+ JCMethodInvocation callToSuper = maker.Apply(List.<JCExpression>nil(),
+ maker.Select(maker.Ident(type.toName("super")), name),
+ List.<JCExpression>of(maker.Ident(type.toName(INSTANCE_VARIABLE_NAME))));
+ body.append(maker.Exec(callToSuper));
+ }
+
+ // Call the builder implemention's helper method that actually fills the values from the instance.
+ JCMethodInvocation callStaticFillValuesMethod = maker.Apply(List.<JCExpression>nil(),
+ maker.Select(maker.Ident(type.toName(builderImplClassName)), type.toName(STATIC_FILL_VALUES_METHOD_NAME)),
+ List.<JCExpression>of(maker.Ident(type.toName(INSTANCE_VARIABLE_NAME)), maker.Ident(type.toName("this"))));
+ body.append(maker.Exec(callStaticFillValuesMethod));
+
+ JCReturn returnStatement = maker.Return(maker.Apply(List.<JCExpression>nil(), maker.Ident(type.toName(SELF_METHOD)), List.<JCExpression>nil()));
+ body.append(returnStatement);
+ JCBlock bodyBlock = maker.Block(0, body.toList());
+
+ return maker.MethodDef(modifiers, name, returnType, List.<JCTypeParameter>nil(), List.of(param), List.<JCExpression>nil(), bodyBlock, null);
+ }
+
+ /**
+ * Generates a <code>$fillValuesFromInstanceIntoBuilder()</code> method in
+ * the builder implementation class that copies all fields from the instance
+ * to the builder. It looks like this:
+ *
+ * <pre>
+ * protected B $fillValuesFromInstanceIntoBuilder(Foobar instance, FoobarBuilder&lt;?, ?&gt; b) {
+ * b.field(instance.field);
+ * }
+ * </pre>
+ */
+ private JCMethodDecl generateStaticFillValuesMethod(JavacNode type, String builderClassname, List<JCTypeParameter> typeParams, java.util.List<BuilderFieldData> builderFields) {
+ JavacTreeMaker maker = type.getTreeMaker();
+ List<JCAnnotation> annotations = List.nil();
+ JCModifiers modifiers = maker.Modifiers(Flags.PRIVATE | Flags.STATIC, annotations);
+ Name name = type.toName(STATIC_FILL_VALUES_METHOD_NAME);
+ JCExpression returnType = maker.TypeIdent(CTC_VOID);
+
+ // 1st parameter: "Foobar instance"
+ JCVariableDecl paramInstance = maker.VarDef(maker.Modifiers(Flags.LocalVarFlags), type.toName(INSTANCE_VARIABLE_NAME), cloneSelfType(type), null);
+
+ // 2nd parameter: "FoobarBuilder<?, ?> b" (plus generics on the annotated type)
+ // First add all generics that are present on the parent type.
+ ListBuffer<JCExpression> typeParamsForBuilderParameter = getTypeParamExpressions(typeParams, maker);
+ // Now add the <?, ?>.
+ JCWildcard wildcard = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null);
+ typeParamsForBuilderParameter.add(wildcard);
+ wildcard = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null);
+ typeParamsForBuilderParameter.add(wildcard);
+ JCTypeApply builderType = maker.TypeApply(maker.Ident(type.toName(builderClassname)), typeParamsForBuilderParameter.toList());
+ JCVariableDecl paramBuilder = maker.VarDef(maker.Modifiers(Flags.LocalVarFlags), type.toName(BUILDER_VARIABLE_NAME), builderType, null);
+
+ ListBuffer<JCStatement> body = new ListBuffer<JCStatement>();
+
+ // Call the builder's setter methods to fill the values from the instance.
+ for (BuilderFieldData bfd : builderFields) {
+ JCExpressionStatement exec = createSetterCallWithInstanceValue(bfd, type, maker);
+ body.append(exec);
+ }
+
+ JCBlock bodyBlock = maker.Block(0, body.toList());
+
+ return maker.MethodDef(modifiers, name, returnType, copyTypeParams(type, typeParams), List.of(paramInstance, paramBuilder), List.<JCExpression>nil(), bodyBlock, null);
+ }
+
+ private JCExpressionStatement createSetterCallWithInstanceValue(BuilderFieldData bfd, JavacNode type, JavacTreeMaker maker) {
+ JCExpression[] tgt = new JCExpression[bfd.singularData == null ? 1 : 2];
+ if (bfd.obtainVia == null || !bfd.obtainVia.field().isEmpty()) {
+ for (int i = 0; i < tgt.length; i++) {
+ tgt[i] = maker.Select(maker.Ident(type.toName(INSTANCE_VARIABLE_NAME)), bfd.obtainVia == null ? bfd.rawName : type.toName(bfd.obtainVia.field()));
+ }
+ } else {
+ if (bfd.obtainVia.isStatic()) {
+ for (int i = 0; i < tgt.length; i++) {
+ JCExpression c = maker.Select(maker.Ident(type.toName(type.getName())), type.toName(bfd.obtainVia.method()));
+ tgt[i] = maker.Apply(List.<JCExpression>nil(), c, List.<JCExpression>of(maker.Ident(type.toName(INSTANCE_VARIABLE_NAME))));
+ }
+ } else {
+ for (int i = 0; i < tgt.length; i++) {
+ JCExpression c = maker.Select(maker.Ident(type.toName(INSTANCE_VARIABLE_NAME)), type.toName(bfd.obtainVia.method()));
+ tgt[i] = maker.Apply(List.<JCExpression>nil(), c, List.<JCExpression>nil());
+ }
+ }
+ }
+
+ JCExpression arg;
+ if (bfd.singularData == null) {
+ arg = tgt[0];
+ } else {
+ JCExpression eqNull = maker.Binary(CTC_EQUAL, tgt[0], maker.Literal(CTC_BOT, null));
+ JCExpression emptyList = maker.Apply(List.<JCExpression>nil(), chainDots(type, "java", "util", "Collections", "emptyList"), List.<JCExpression>nil());
+ arg = maker.Conditional(eqNull, emptyList, tgt[1]);
+ }
+ JCMethodInvocation apply = maker.Apply(List.<JCExpression>nil(), maker.Select(maker.Ident(type.toName(BUILDER_VARIABLE_NAME)), bfd.name), List.of(arg));
+ JCExpressionStatement exec = maker.Exec(apply);
+ return exec;
+ }
+
private JCMethodDecl generateAbstractSelfMethod(JavacNode type, boolean override, String builderGenericName) {
JavacTreeMaker maker = type.getTreeMaker();
List<JCAnnotation> annotations = List.nil();
@@ -506,7 +709,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
JCModifiers modifiers = maker.Modifiers(Flags.PROTECTED | Flags.ABSTRACT, annotations);
Name name = type.toName(SELF_METHOD);
JCExpression returnType = maker.Ident(type.toName(builderGenericName));
-
+
return maker.MethodDef(modifiers, name, returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), null, null);
}
@@ -538,7 +741,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
return maker.MethodDef(modifiers, name, returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), null, null);
}
- private JCMethodDecl generateBuildMethod(String buildName, JCExpression returnType, JavacNode type, List<JCExpression> thrownExceptions) {
+ private JCMethodDecl generateBuildMethod(String buildName, JavacNode returnType, JavacNode type, List<JCExpression> thrownExceptions) {
JavacTreeMaker maker = type.getTreeMaker();
JCExpression call;
@@ -546,7 +749,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
// Use a constructor that only has this builder as parameter.
List<JCExpression> builderArg = List.<JCExpression>of(maker.Ident(type.toName("this")));
- call = maker.NewClass(null, List.<JCExpression>nil(), returnType, builderArg, null);
+ call = maker.NewClass(null, List.<JCExpression>nil(), cloneSelfType(returnType), builderArg, null);
statements.append(maker.Return(call));
JCBlock body = maker.Block(0, statements.toList());
@@ -554,7 +757,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(type, "Override"), List.<JCExpression>nil());
JCModifiers modifiers = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation));
- return maker.MethodDef(modifiers, type.toName(buildName), returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), thrownExceptions, body, null);
+ return maker.MethodDef(modifiers, type.toName(buildName), cloneSelfType(returnType), List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), thrownExceptions, body, null);
}
private JCMethodDecl generateCleanMethod(java.util.List<BuilderFieldData> builderFields, JavacNode type, JCTree source) {
@@ -618,13 +821,13 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
}};
if (fieldNode.singularData == null || fieldNode.singularData.getSingularizer() == null) {
- generateSimpleSetterMethodForBuilder(builderType, deprecate, fieldNode.createdFields.get(0), fieldNode.nameOfSetFlag, source, true, true, returnTypeMaker.make(), returnStatementMaker.make(), fieldNode.annotations);
+ generateSimpleSetterMethodForBuilder(builderType, deprecate, fieldNode.createdFields.get(0), fieldNode.nameOfSetFlag, source, true, returnTypeMaker.make(), returnStatementMaker.make(), fieldNode.annotations);
} else {
fieldNode.singularData.getSingularizer().generateMethods(fieldNode.singularData, deprecate, builderType, source.get(), true, returnTypeMaker, returnStatementMaker);
}
}
- private void generateSimpleSetterMethodForBuilder(JavacNode builderType, boolean deprecate, JavacNode fieldNode, Name nameOfSetFlag, JavacNode source, boolean fluent, boolean chain, JCExpression returnType, JCStatement returnStatement, List<JCAnnotation> annosOnParam) {
+ private void generateSimpleSetterMethodForBuilder(JavacNode builderType, boolean deprecate, JavacNode fieldNode, Name nameOfSetFlag, JavacNode source, boolean fluent, JCExpression returnType, JCStatement returnStatement, List<JCAnnotation> annosOnParam) {
Name fieldName = ((JCVariableDecl) fieldNode.get()).name;
for (JavacNode child : builderType.down()) {
diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
index e4e40095..c97c7ede 100644
--- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java
+++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
@@ -58,6 +58,7 @@ import lombok.experimental.Tolerate;
import lombok.javac.Javac;
import lombok.javac.JavacNode;
import lombok.javac.JavacTreeMaker;
+import lombok.permit.Permit;
import com.sun.tools.javac.code.BoundKind;
import com.sun.tools.javac.code.Flags;
@@ -1049,10 +1050,9 @@ public class JavacHandlerUtil {
if (TYPE != null) return;
if (!in.getName().equals("com.sun.tools.javac.tree.JCTree$JCAnnotatedType")) return;
try {
- CONSTRUCTOR = in.getDeclaredConstructor(List.class, JCExpression.class);
- CONSTRUCTOR.setAccessible(true);
- ANNOTATIONS = in.getDeclaredField("annotations");
- UNDERLYING_TYPE = in.getDeclaredField("underlyingType");
+ CONSTRUCTOR = Permit.getConstructor(in, List.class, JCExpression.class);
+ ANNOTATIONS = Permit.getField(in, "annotations");
+ UNDERLYING_TYPE = Permit.getField(in, "underlyingType");
TYPE = in;
} catch (Exception ignore) {}
}
@@ -1102,9 +1102,9 @@ public class JavacHandlerUtil {
Method r = null;
Method e = null;
try {
- f = ClassSymbol.class.getField("members_field");
- r = f.getType().getMethod("remove", Symbol.class);
- e = f.getType().getMethod("enter", Symbol.class);
+ f = Permit.getField(ClassSymbol.class, "members_field");
+ r = Permit.getMethod(f.getType(), "remove", Symbol.class);
+ e = Permit.getMethod(f.getType(), "enter", Symbol.class);
} catch (Exception ex) {}
membersField = f;
removeMethod = r;