mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-13 06:15:41 +00:00
SuperBuilder: generate fillValuesFrom method (ecj)
This commit is contained in:
1 parent
abb0d2374e
commit
1f3688fdba
4 files changed
+121
-30
No files matched your search
@@ -105,7 +105,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
return ((Boolean) expr).booleanValue();
|
||||
}
|
||||
|
||||
private static class BuilderFieldData {
|
||||
public static class BuilderFieldData {
|
||||
TypeReference type;
|
||||
char[] rawName;
|
||||
char[] name;
|
||||
|
||||
@@ -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,40 +104,31 @@ 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 char[] TO_BUILDER_METHOD_NAME = "toBuilder".toCharArray();
|
||||
private static final char[] FILL_VALUES_METHOD_NAME = "$fillValuesFrom".toCharArray();
|
||||
private static final char[] EMPTY_LIST = "emptyList".toCharArray();
|
||||
|
||||
private static final AbstractMethodDeclaration[] EMPTY_METHODS = {};
|
||||
|
||||
private static class BuilderFieldData {
|
||||
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>();
|
||||
@@ -293,7 +290,12 @@ 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, 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));
|
||||
@@ -532,6 +534,93 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
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);
|
||||
* this.field(instance.field);
|
||||
* return self();
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
private MethodDeclaration generateFillValuesMethod(EclipseNode tdParent, boolean inherited, String builderGenericName, String classGenericName, TypeParameter[] typeParams, java.util.List<BuilderFieldData> builderFields, ASTNode source) {
|
||||
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);
|
||||
|
||||
final String instanceVariableName = "instance";
|
||||
TypeReference builderType = createTypeReferenceWithTypeParameters(classGenericName, typeParams);
|
||||
out.arguments = new Argument[] {new Argument(instanceVariableName.toCharArray(), 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(instanceVariableName.toCharArray(), 0)};
|
||||
body.add(callToSuper);
|
||||
}
|
||||
|
||||
// Call the builder's setter methods to fill the values from the instance.
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
MessageSend exec = createSetterCallWithInstanceValue(bfd, instanceVariableName, tdParent, source);
|
||||
body.add(exec);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private MessageSend createSetterCallWithInstanceValue(BuilderFieldData bfd, final String instanceVariableName, 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(instanceVariableName.toCharArray(), 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 ThisReference(0, 0);
|
||||
obtainExpr.selector = obtainName.toCharArray();
|
||||
if (obtainIsStatic) obtainExpr.arguments = new Expression[] {new ThisReference(0, 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 = ThisReference.implicitThis();
|
||||
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;
|
||||
|
||||
@@ -236,8 +236,10 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
injectFieldAndMarkGenerated(builderType, uncleanField);
|
||||
}
|
||||
|
||||
// Generate $fillValuesFrom() method in the abstract builder.
|
||||
injectMethod(builderType, generateFillValuesMethod(tdParent, superclassBuilderClassExpression != null, builderGenericName, classGenericName, builderFields));
|
||||
if (toBuilder) {
|
||||
// Generate $fillValuesFrom() method in the abstract builder.
|
||||
injectMethod(builderType, generateFillValuesMethod(tdParent, superclassBuilderClassExpression != null, builderGenericName, classGenericName, builderFields));
|
||||
}
|
||||
|
||||
// Generate abstract self() and build() methods in the abstract builder.
|
||||
injectMethod(builderType, generateAbstractSelfMethod(tdParent, superclassBuilderClassExpression != null, builderGenericName));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import java.util.List;
|
||||
|
||||
public class SuperBuilderBasic {
|
||||
public static @lombok.experimental.SuperBuilder class Parent {
|
||||
public class SuperBuilderBasicToBuilder {
|
||||
public static @lombok.experimental.SuperBuilder(toBuilder = true) class Parent {
|
||||
public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder<C extends Parent, B extends ParentBuilder<C, B>> {
|
||||
private @java.lang.SuppressWarnings("all") int field1;
|
||||
private @java.lang.SuppressWarnings("all") java.util.ArrayList<String> items;
|
||||
@@ -9,8 +9,8 @@ public class SuperBuilderBasic {
|
||||
super();
|
||||
}
|
||||
protected @java.lang.SuppressWarnings("all") B $fillValuesFrom(final C instance) {
|
||||
this.field1(instance.field1);
|
||||
this.items(instance.items == null ? java.util.Collections.emptyList() : instance.items);
|
||||
field1(instance.field1);
|
||||
items(((instance.items == null) ? java.util.Collections.emptyList() : instance.items));
|
||||
return self();
|
||||
}
|
||||
protected abstract @java.lang.SuppressWarnings("all") B self();
|
||||
@@ -37,7 +37,7 @@ public class SuperBuilderBasic {
|
||||
return self();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
|
||||
return (((("SuperBuilderBasic.Parent.ParentBuilder(field1=" + this.field1) + ", items=") + this.items) + ")");
|
||||
return (((("SuperBuilderBasicToBuilder.Parent.ParentBuilder(field1=" + this.field1) + ", items=") + this.items) + ")");
|
||||
}
|
||||
}
|
||||
private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends ParentBuilder<Parent, ParentBuilderImpl> {
|
||||
@@ -76,7 +76,7 @@ public class SuperBuilderBasic {
|
||||
return new ParentBuilderImpl().$fillValuesFrom(this);
|
||||
}
|
||||
}
|
||||
public static @lombok.experimental.SuperBuilder class Child extends Parent {
|
||||
public static @lombok.experimental.SuperBuilder(toBuilder = true) class Child extends Parent {
|
||||
public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder<C extends Child, B extends ChildBuilder<C, B>> extends Parent.ParentBuilder<C, B> {
|
||||
private @java.lang.SuppressWarnings("all") double field3;
|
||||
public ChildBuilder() {
|
||||
@@ -84,7 +84,7 @@ public class SuperBuilderBasic {
|
||||
}
|
||||
protected @java.lang.Override @java.lang.SuppressWarnings("all") B $fillValuesFrom(C instance) {
|
||||
super.$fillValuesFrom(instance);
|
||||
this.field3(instance.field3);
|
||||
field3(instance.field3);
|
||||
return self();
|
||||
}
|
||||
protected abstract @java.lang.Override @java.lang.SuppressWarnings("all") B self();
|
||||
@@ -94,7 +94,7 @@ public class SuperBuilderBasic {
|
||||
return self();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
|
||||
return (((("SuperBuilderBasic.Child.ChildBuilder(super=" + super.toString()) + ", field3=") + this.field3) + ")");
|
||||
return (((("SuperBuilderBasicToBuilder.Child.ChildBuilder(super=" + super.toString()) + ", field3=") + this.field3) + ")");
|
||||
}
|
||||
}
|
||||
private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends ChildBuilder<Child, ChildBuilderImpl> {
|
||||
|
||||
Reference in new issue
Block a user