mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-14 12:16:49 +00:00
Merge branch 'superToBuilder' of git://github.com/janrieke/lombok into janrieke-superToBuilder
This commit is contained in:
commit
06455de367
15 files changed
+1474
-83
No files matched your search
@@ -105,7 +105,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
return ((Boolean) expr).booleanValue();
|
||||
}
|
||||
|
||||
private static class BuilderFieldData {
|
||||
static class BuilderFieldData {
|
||||
Annotation[] annotations;
|
||||
TypeReference type;
|
||||
char[] rawName;
|
||||
|
||||
@@ -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>();
|
||||
@@ -297,7 +298,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,7 +332,8 @@ 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;
|
||||
}
|
||||
@@ -337,7 +346,20 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
annotationNode.addError("@SuperBuilder does not support customized builders. Use @Builder instead.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
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));
|
||||
@@ -441,7 +463,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 +477,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 +490,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 +501,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 +555,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<?, ?> 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<?, ?> 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;
|
||||
|
||||
@@ -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 @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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -37,11 +37,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 +63,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 +71,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 +104,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 +187,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,7 +225,7 @@ 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;
|
||||
@@ -245,6 +239,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 +272,26 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
// 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));
|
||||
injectMethod(builderImplType, generateBuildMethod(buildMethodName, tdParent, builderImplType, thrownExceptions));
|
||||
|
||||
recursiveSetGeneratedBy(builderImplType.get(), ast, annotationNode.getContext());
|
||||
}
|
||||
@@ -298,15 +300,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 +335,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 +377,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 +429,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 +515,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<?, ?> 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<?, ?> 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 +685,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 +717,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 +725,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 +733,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 +797,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()) {
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
public class SuperBuilderAbstractToBuilder {
|
||||
public static class Parent {
|
||||
int parentField;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static abstract class ParentBuilder<C extends Parent, B extends ParentBuilder<C, B>> {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private int parentField;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected B $fillValuesFrom(final C instance) {
|
||||
ParentBuilder.$fillValuesFromInstanceIntoBuilder(instance, this);
|
||||
return self();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private static void $fillValuesFromInstanceIntoBuilder(final Parent instance, final ParentBuilder<?, ?> b) {
|
||||
b.parentField(instance.parentField);
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected abstract B self();
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public abstract C build();
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B parentField(final int parentField) {
|
||||
this.parentField = parentField;
|
||||
return self();
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public java.lang.String toString() {
|
||||
return "SuperBuilderAbstractToBuilder.Parent.ParentBuilder(parentField=" + this.parentField + ")";
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private static final class ParentBuilderImpl extends ParentBuilder<Parent, ParentBuilderImpl> {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private ParentBuilderImpl() {
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected ParentBuilderImpl self() {
|
||||
return this;
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public Parent build() {
|
||||
return new Parent(this);
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected Parent(final ParentBuilder<?, ?> b) {
|
||||
this.parentField = b.parentField;
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static ParentBuilder<?, ?> builder() {
|
||||
return new ParentBuilderImpl();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public ParentBuilder<?, ?> toBuilder() {
|
||||
return new ParentBuilderImpl().$fillValuesFrom(this);
|
||||
}
|
||||
}
|
||||
public static abstract class Child extends Parent {
|
||||
double childField;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static abstract class ChildBuilder<C extends Child, B extends ChildBuilder<C, B>> extends Parent.ParentBuilder<C, B> {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private double childField;
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected B $fillValuesFrom(final C instance) {
|
||||
super.$fillValuesFrom(instance);
|
||||
ChildBuilder.$fillValuesFromInstanceIntoBuilder(instance, this);
|
||||
return self();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private static void $fillValuesFromInstanceIntoBuilder(final Child instance, final ChildBuilder<?, ?> b) {
|
||||
b.childField(instance.childField);
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected abstract B self();
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public abstract C build();
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B childField(final double childField) {
|
||||
this.childField = childField;
|
||||
return self();
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public java.lang.String toString() {
|
||||
return "SuperBuilderAbstractToBuilder.Child.ChildBuilder(super=" + super.toString() + ", childField=" + this.childField + ")";
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected Child(final ChildBuilder<?, ?> b) {
|
||||
super(b);
|
||||
this.childField = b.childField;
|
||||
}
|
||||
}
|
||||
public static class GrandChild extends Child {
|
||||
String grandChildField;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static abstract class GrandChildBuilder<C extends GrandChild, B extends GrandChildBuilder<C, B>> extends Child.ChildBuilder<C, B> {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private String grandChildField;
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected B $fillValuesFrom(final C instance) {
|
||||
super.$fillValuesFrom(instance);
|
||||
GrandChildBuilder.$fillValuesFromInstanceIntoBuilder(instance, this);
|
||||
return self();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private static void $fillValuesFromInstanceIntoBuilder(final GrandChild instance, final GrandChildBuilder<?, ?> b) {
|
||||
b.grandChildField(instance.grandChildField);
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected abstract B self();
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public abstract C build();
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B grandChildField(final String grandChildField) {
|
||||
this.grandChildField = grandChildField;
|
||||
return self();
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public java.lang.String toString() {
|
||||
return "SuperBuilderAbstractToBuilder.GrandChild.GrandChildBuilder(super=" + super.toString() + ", grandChildField=" + this.grandChildField + ")";
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private static final class GrandChildBuilderImpl extends GrandChildBuilder<GrandChild, GrandChildBuilderImpl> {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private GrandChildBuilderImpl() {
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected GrandChildBuilderImpl self() {
|
||||
return this;
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public GrandChild build() {
|
||||
return new GrandChild(this);
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected GrandChild(final GrandChildBuilder<?, ?> b) {
|
||||
super(b);
|
||||
this.grandChildField = b.grandChildField;
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static GrandChildBuilder<?, ?> builder() {
|
||||
return new GrandChildBuilderImpl();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public GrandChildBuilder<?, ?> toBuilder() {
|
||||
return new GrandChildBuilderImpl().$fillValuesFrom(this);
|
||||
}
|
||||
}
|
||||
public static void test() {
|
||||
GrandChild x = GrandChild.builder().grandChildField("").parentField(5).childField(2.5).build().toBuilder().build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
import java.util.List;
|
||||
public class SuperBuilderBasicToBuilder {
|
||||
public static class Parent {
|
||||
private int field1;
|
||||
int obtainViaField;
|
||||
int obtainViaMethod;
|
||||
String obtainViaStaticMethod;
|
||||
List<String> items;
|
||||
private int method() {
|
||||
return 2;
|
||||
}
|
||||
private static String staticMethod(Parent instance) {
|
||||
return "staticMethod";
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static abstract class ParentBuilder<C extends Parent, B extends ParentBuilder<C, B>> {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private int field1;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private int obtainViaField;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private int obtainViaMethod;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private String obtainViaStaticMethod;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private java.util.ArrayList<String> items;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected B $fillValuesFrom(final C instance) {
|
||||
ParentBuilder.$fillValuesFromInstanceIntoBuilder(instance, this);
|
||||
return self();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private static void $fillValuesFromInstanceIntoBuilder(final Parent instance, final ParentBuilder<?, ?> b) {
|
||||
b.field1(instance.field1);
|
||||
b.obtainViaField(instance.field1);
|
||||
b.obtainViaMethod(instance.method());
|
||||
b.obtainViaStaticMethod(Parent.staticMethod(instance));
|
||||
b.items(instance.items == null ? java.util.Collections.emptyList() : instance.items);
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected abstract B self();
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public abstract C build();
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B field1(final int field1) {
|
||||
this.field1 = field1;
|
||||
return self();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B obtainViaField(final int obtainViaField) {
|
||||
this.obtainViaField = obtainViaField;
|
||||
return self();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B obtainViaMethod(final int obtainViaMethod) {
|
||||
this.obtainViaMethod = obtainViaMethod;
|
||||
return self();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B obtainViaStaticMethod(final String obtainViaStaticMethod) {
|
||||
this.obtainViaStaticMethod = obtainViaStaticMethod;
|
||||
return self();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B item(final String item) {
|
||||
if (this.items == null) this.items = new java.util.ArrayList<String>();
|
||||
this.items.add(item);
|
||||
return self();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B items(final java.util.Collection<? extends String> items) {
|
||||
if (this.items == null) this.items = new java.util.ArrayList<String>();
|
||||
this.items.addAll(items);
|
||||
return self();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B clearItems() {
|
||||
if (this.items != null) this.items.clear();
|
||||
return self();
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public java.lang.String toString() {
|
||||
return "SuperBuilderBasicToBuilder.Parent.ParentBuilder(field1=" + this.field1 + ", obtainViaField=" + this.obtainViaField + ", obtainViaMethod=" + this.obtainViaMethod + ", obtainViaStaticMethod=" + this.obtainViaStaticMethod + ", items=" + this.items + ")";
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private static final class ParentBuilderImpl extends ParentBuilder<Parent, ParentBuilderImpl> {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private ParentBuilderImpl() {
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected ParentBuilderImpl self() {
|
||||
return this;
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public Parent build() {
|
||||
return new Parent(this);
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected Parent(final ParentBuilder<?, ?> b) {
|
||||
this.field1 = b.field1;
|
||||
this.obtainViaField = b.obtainViaField;
|
||||
this.obtainViaMethod = b.obtainViaMethod;
|
||||
this.obtainViaStaticMethod = b.obtainViaStaticMethod;
|
||||
java.util.List<String> items;
|
||||
switch (b.items == null ? 0 : b.items.size()) {
|
||||
case 0:
|
||||
items = java.util.Collections.emptyList();
|
||||
break;
|
||||
case 1:
|
||||
items = java.util.Collections.singletonList(b.items.get(0));
|
||||
break;
|
||||
default:
|
||||
items = java.util.Collections.unmodifiableList(new java.util.ArrayList<String>(b.items));
|
||||
}
|
||||
this.items = items;
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static ParentBuilder<?, ?> builder() {
|
||||
return new ParentBuilderImpl();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public ParentBuilder<?, ?> toBuilder() {
|
||||
return new ParentBuilderImpl().$fillValuesFrom(this);
|
||||
}
|
||||
}
|
||||
public static class Child extends Parent {
|
||||
private double field3;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static abstract class ChildBuilder<C extends Child, B extends ChildBuilder<C, B>> extends Parent.ParentBuilder<C, B> {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private double field3;
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected B $fillValuesFrom(final C instance) {
|
||||
super.$fillValuesFrom(instance);
|
||||
ChildBuilder.$fillValuesFromInstanceIntoBuilder(instance, this);
|
||||
return self();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private static void $fillValuesFromInstanceIntoBuilder(final Child instance, final ChildBuilder<?, ?> b) {
|
||||
b.field3(instance.field3);
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected abstract B self();
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public abstract C build();
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B field3(final double field3) {
|
||||
this.field3 = field3;
|
||||
return self();
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public java.lang.String toString() {
|
||||
return "SuperBuilderBasicToBuilder.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")";
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private static final class ChildBuilderImpl extends ChildBuilder<Child, ChildBuilderImpl> {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private ChildBuilderImpl() {
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected ChildBuilderImpl self() {
|
||||
return this;
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public Child build() {
|
||||
return new Child(this);
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected Child(final ChildBuilder<?, ?> b) {
|
||||
super(b);
|
||||
this.field3 = b.field3;
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static ChildBuilder<?, ?> builder() {
|
||||
return new ChildBuilderImpl();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public ChildBuilder<?, ?> toBuilder() {
|
||||
return new ChildBuilderImpl().$fillValuesFrom(this);
|
||||
}
|
||||
}
|
||||
public static void test() {
|
||||
Child x = Child.builder().field3(0.0).field1(5).item("").build().toBuilder().build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
import java.util.List;
|
||||
public class SuperBuilderWithGenericsAndToBuilder {
|
||||
public static class Parent<A> {
|
||||
A field1;
|
||||
List<String> items;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static abstract class ParentBuilder<A, C extends Parent<A>, B extends ParentBuilder<A, C, B>> {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private A field1;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private java.util.ArrayList<String> items;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected B $fillValuesFrom(final C instance) {
|
||||
ParentBuilder.$fillValuesFromInstanceIntoBuilder(instance, this);
|
||||
return self();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private static <A> void $fillValuesFromInstanceIntoBuilder(final Parent<A> instance, final ParentBuilder<A, ?, ?> b) {
|
||||
b.field1(instance.field1);
|
||||
b.items(instance.items == null ? java.util.Collections.emptyList() : instance.items);
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected abstract B self();
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public abstract C build();
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B field1(final A field1) {
|
||||
this.field1 = field1;
|
||||
return self();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B item(final String item) {
|
||||
if (this.items == null) this.items = new java.util.ArrayList<String>();
|
||||
this.items.add(item);
|
||||
return self();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B items(final java.util.Collection<? extends String> items) {
|
||||
if (this.items == null) this.items = new java.util.ArrayList<String>();
|
||||
this.items.addAll(items);
|
||||
return self();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B clearItems() {
|
||||
if (this.items != null) this.items.clear();
|
||||
return self();
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public java.lang.String toString() {
|
||||
return "SuperBuilderWithGenericsAndToBuilder.Parent.ParentBuilder(field1=" + this.field1 + ", items=" + this.items + ")";
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private static final class ParentBuilderImpl<A> extends ParentBuilder<A, Parent<A>, ParentBuilderImpl<A>> {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private ParentBuilderImpl() {
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected ParentBuilderImpl<A> self() {
|
||||
return this;
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public Parent<A> build() {
|
||||
return new Parent<A>(this);
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected Parent(final ParentBuilder<A, ?, ?> b) {
|
||||
this.field1 = b.field1;
|
||||
java.util.List<String> items;
|
||||
switch (b.items == null ? 0 : b.items.size()) {
|
||||
case 0:
|
||||
items = java.util.Collections.emptyList();
|
||||
break;
|
||||
case 1:
|
||||
items = java.util.Collections.singletonList(b.items.get(0));
|
||||
break;
|
||||
default:
|
||||
items = java.util.Collections.unmodifiableList(new java.util.ArrayList<String>(b.items));
|
||||
}
|
||||
this.items = items;
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static <A> ParentBuilder<A, ?, ?> builder() {
|
||||
return new ParentBuilderImpl<A>();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public ParentBuilder<A, ?, ?> toBuilder() {
|
||||
return new ParentBuilderImpl<A>().$fillValuesFrom(this);
|
||||
}
|
||||
}
|
||||
public static class Child<A> extends Parent<A> {
|
||||
double field3;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static abstract class ChildBuilder<A, C extends Child<A>, B extends ChildBuilder<A, C, B>> extends Parent.ParentBuilder<A, C, B> {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private double field3;
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected B $fillValuesFrom(final C instance) {
|
||||
super.$fillValuesFrom(instance);
|
||||
ChildBuilder.$fillValuesFromInstanceIntoBuilder(instance, this);
|
||||
return self();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private static <A> void $fillValuesFromInstanceIntoBuilder(final Child<A> instance, final ChildBuilder<A, ?, ?> b) {
|
||||
b.field3(instance.field3);
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected abstract B self();
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public abstract C build();
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B field3(final double field3) {
|
||||
this.field3 = field3;
|
||||
return self();
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public java.lang.String toString() {
|
||||
return "SuperBuilderWithGenericsAndToBuilder.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")";
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private static final class ChildBuilderImpl<A> extends ChildBuilder<A, Child<A>, ChildBuilderImpl<A>> {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private ChildBuilderImpl() {
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected ChildBuilderImpl<A> self() {
|
||||
return this;
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public Child<A> build() {
|
||||
return new Child<A>(this);
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected Child(final ChildBuilder<A, ?, ?> b) {
|
||||
super(b);
|
||||
this.field3 = b.field3;
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static <A> ChildBuilder<A, ?, ?> builder() {
|
||||
return new ChildBuilderImpl<A>();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public ChildBuilder<A, ?, ?> toBuilder() {
|
||||
return new ChildBuilderImpl<A>().$fillValuesFrom(this);
|
||||
}
|
||||
}
|
||||
public static void test() {
|
||||
Child<Integer> x = Child.<Integer>builder().field3(0.0).field1(5).item("").build().toBuilder().build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
public class SuperBuilderAbstractToBuilder {
|
||||
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 parentField;
|
||||
public ParentBuilder() {
|
||||
super();
|
||||
}
|
||||
protected @java.lang.SuppressWarnings("all") B $fillValuesFrom(final C instance) {
|
||||
ParentBuilder.$fillValuesFromInstanceIntoBuilder(instance, this);
|
||||
return self();
|
||||
}
|
||||
private static @java.lang.SuppressWarnings("all") void $fillValuesFromInstanceIntoBuilder(final Parent instance, final ParentBuilder<?, ?> b) {
|
||||
b.parentField(instance.parentField);
|
||||
}
|
||||
protected abstract @java.lang.SuppressWarnings("all") B self();
|
||||
public abstract @java.lang.SuppressWarnings("all") C build();
|
||||
public @java.lang.SuppressWarnings("all") B parentField(final int parentField) {
|
||||
this.parentField = parentField;
|
||||
return self();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
|
||||
return (("SuperBuilderAbstractToBuilder.Parent.ParentBuilder(parentField=" + this.parentField) + ")");
|
||||
}
|
||||
}
|
||||
private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends ParentBuilder<Parent, ParentBuilderImpl> {
|
||||
private ParentBuilderImpl() {
|
||||
super();
|
||||
}
|
||||
protected @java.lang.Override @java.lang.SuppressWarnings("all") ParentBuilderImpl self() {
|
||||
return this;
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") Parent build() {
|
||||
return new Parent(this);
|
||||
}
|
||||
}
|
||||
int parentField;
|
||||
protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder<?, ?> b) {
|
||||
super();
|
||||
this.parentField = b.parentField;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") ParentBuilder<?, ?> toBuilder() {
|
||||
return new ParentBuilderImpl().$fillValuesFrom(this);
|
||||
}
|
||||
public static @java.lang.SuppressWarnings("all") ParentBuilder<?, ?> builder() {
|
||||
return new ParentBuilderImpl();
|
||||
}
|
||||
}
|
||||
public static abstract @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 childField;
|
||||
public ChildBuilder() {
|
||||
super();
|
||||
}
|
||||
protected @java.lang.Override @java.lang.SuppressWarnings("all") B $fillValuesFrom(final C instance) {
|
||||
super.$fillValuesFrom(instance);
|
||||
ChildBuilder.$fillValuesFromInstanceIntoBuilder(instance, this);
|
||||
return self();
|
||||
}
|
||||
private static @java.lang.SuppressWarnings("all") void $fillValuesFromInstanceIntoBuilder(final Child instance, final ChildBuilder<?, ?> b) {
|
||||
b.childField(instance.childField);
|
||||
}
|
||||
protected abstract @java.lang.Override @java.lang.SuppressWarnings("all") B self();
|
||||
public abstract @java.lang.Override @java.lang.SuppressWarnings("all") C build();
|
||||
public @java.lang.SuppressWarnings("all") B childField(final double childField) {
|
||||
this.childField = childField;
|
||||
return self();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
|
||||
return (((("SuperBuilderAbstractToBuilder.Child.ChildBuilder(super=" + super.toString()) + ", childField=") + this.childField) + ")");
|
||||
}
|
||||
}
|
||||
double childField;
|
||||
protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder<?, ?> b) {
|
||||
super(b);
|
||||
this.childField = b.childField;
|
||||
}
|
||||
}
|
||||
public static @lombok.experimental.SuperBuilder(toBuilder = true) class GrandChild extends Child {
|
||||
public static abstract @java.lang.SuppressWarnings("all") class GrandChildBuilder<C extends GrandChild, B extends GrandChildBuilder<C, B>> extends Child.ChildBuilder<C, B> {
|
||||
private @java.lang.SuppressWarnings("all") String grandChildField;
|
||||
public GrandChildBuilder() {
|
||||
super();
|
||||
}
|
||||
protected @java.lang.Override @java.lang.SuppressWarnings("all") B $fillValuesFrom(final C instance) {
|
||||
super.$fillValuesFrom(instance);
|
||||
GrandChildBuilder.$fillValuesFromInstanceIntoBuilder(instance, this);
|
||||
return self();
|
||||
}
|
||||
private static @java.lang.SuppressWarnings("all") void $fillValuesFromInstanceIntoBuilder(final GrandChild instance, final GrandChildBuilder<?, ?> b) {
|
||||
b.grandChildField(instance.grandChildField);
|
||||
}
|
||||
protected abstract @java.lang.Override @java.lang.SuppressWarnings("all") B self();
|
||||
public abstract @java.lang.Override @java.lang.SuppressWarnings("all") C build();
|
||||
public @java.lang.SuppressWarnings("all") B grandChildField(final String grandChildField) {
|
||||
this.grandChildField = grandChildField;
|
||||
return self();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
|
||||
return (((("SuperBuilderAbstractToBuilder.GrandChild.GrandChildBuilder(super=" + super.toString()) + ", grandChildField=") + this.grandChildField) + ")");
|
||||
}
|
||||
}
|
||||
private static final @java.lang.SuppressWarnings("all") class GrandChildBuilderImpl extends GrandChildBuilder<GrandChild, GrandChildBuilderImpl> {
|
||||
private GrandChildBuilderImpl() {
|
||||
super();
|
||||
}
|
||||
protected @java.lang.Override @java.lang.SuppressWarnings("all") GrandChildBuilderImpl self() {
|
||||
return this;
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") GrandChild build() {
|
||||
return new GrandChild(this);
|
||||
}
|
||||
}
|
||||
String grandChildField;
|
||||
protected @java.lang.SuppressWarnings("all") GrandChild(final GrandChildBuilder<?, ?> b) {
|
||||
super(b);
|
||||
this.grandChildField = b.grandChildField;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") GrandChildBuilder<?, ?> toBuilder() {
|
||||
return new GrandChildBuilderImpl().$fillValuesFrom(this);
|
||||
}
|
||||
public static @java.lang.SuppressWarnings("all") GrandChildBuilder<?, ?> builder() {
|
||||
return new GrandChildBuilderImpl();
|
||||
}
|
||||
}
|
||||
public SuperBuilderAbstractToBuilder() {
|
||||
super();
|
||||
}
|
||||
public static void test() {
|
||||
GrandChild x = GrandChild.builder().grandChildField("").parentField(5).childField(2.5).build().toBuilder().build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
import java.util.List;
|
||||
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") int obtainViaField;
|
||||
private @java.lang.SuppressWarnings("all") int obtainViaMethod;
|
||||
private @java.lang.SuppressWarnings("all") String obtainViaStaticMethod;
|
||||
private @java.lang.SuppressWarnings("all") java.util.ArrayList<String> items;
|
||||
public ParentBuilder() {
|
||||
super();
|
||||
}
|
||||
protected @java.lang.SuppressWarnings("all") B $fillValuesFrom(final C instance) {
|
||||
ParentBuilder.$fillValuesFromInstanceIntoBuilder(instance, this);
|
||||
return self();
|
||||
}
|
||||
private static @java.lang.SuppressWarnings("all") void $fillValuesFromInstanceIntoBuilder(final Parent instance, final ParentBuilder<?, ?> b) {
|
||||
b.field1(instance.field1);
|
||||
b.obtainViaField(instance.field1);
|
||||
b.obtainViaMethod(instance.method());
|
||||
b.obtainViaStaticMethod(Parent.staticMethod(instance));
|
||||
b.items(((instance.items == null) ? java.util.Collections.emptyList() : instance.items));
|
||||
}
|
||||
protected abstract @java.lang.SuppressWarnings("all") B self();
|
||||
public abstract @java.lang.SuppressWarnings("all") C build();
|
||||
public @java.lang.SuppressWarnings("all") B field1(final int field1) {
|
||||
this.field1 = field1;
|
||||
return self();
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") B obtainViaField(final int obtainViaField) {
|
||||
this.obtainViaField = obtainViaField;
|
||||
return self();
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") B obtainViaMethod(final int obtainViaMethod) {
|
||||
this.obtainViaMethod = obtainViaMethod;
|
||||
return self();
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") B obtainViaStaticMethod(final String obtainViaStaticMethod) {
|
||||
this.obtainViaStaticMethod = obtainViaStaticMethod;
|
||||
return self();
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") B item(final String item) {
|
||||
if ((this.items == null))
|
||||
this.items = new java.util.ArrayList<String>();
|
||||
this.items.add(item);
|
||||
return self();
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") B items(final java.util.Collection<? extends String> items) {
|
||||
if ((this.items == null))
|
||||
this.items = new java.util.ArrayList<String>();
|
||||
this.items.addAll(items);
|
||||
return self();
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") B clearItems() {
|
||||
if ((this.items != null))
|
||||
this.items.clear();
|
||||
return self();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
|
||||
return (((((((((("SuperBuilderBasicToBuilder.Parent.ParentBuilder(field1=" + this.field1) + ", obtainViaField=") + this.obtainViaField) + ", obtainViaMethod=") + this.obtainViaMethod) + ", obtainViaStaticMethod=") + this.obtainViaStaticMethod) + ", items=") + this.items) + ")");
|
||||
}
|
||||
}
|
||||
private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends ParentBuilder<Parent, ParentBuilderImpl> {
|
||||
private ParentBuilderImpl() {
|
||||
super();
|
||||
}
|
||||
protected @java.lang.Override @java.lang.SuppressWarnings("all") ParentBuilderImpl self() {
|
||||
return this;
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") Parent build() {
|
||||
return new Parent(this);
|
||||
}
|
||||
}
|
||||
private int field1;
|
||||
@lombok.Builder.ObtainVia(field = "field1") int obtainViaField;
|
||||
@lombok.Builder.ObtainVia(method = "method") int obtainViaMethod;
|
||||
@lombok.Builder.ObtainVia(method = "staticMethod",isStatic = true) String obtainViaStaticMethod;
|
||||
@lombok.Singular List<String> items;
|
||||
private int method() {
|
||||
return 2;
|
||||
}
|
||||
private static String staticMethod(Parent instance) {
|
||||
return "staticMethod";
|
||||
}
|
||||
protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder<?, ?> b) {
|
||||
super();
|
||||
this.field1 = b.field1;
|
||||
this.obtainViaField = b.obtainViaField;
|
||||
this.obtainViaMethod = b.obtainViaMethod;
|
||||
this.obtainViaStaticMethod = b.obtainViaStaticMethod;
|
||||
java.util.List<String> items;
|
||||
switch (((b.items == null) ? 0 : b.items.size())) {
|
||||
case 0 :
|
||||
items = java.util.Collections.emptyList();
|
||||
break;
|
||||
case 1 :
|
||||
items = java.util.Collections.singletonList(b.items.get(0));
|
||||
break;
|
||||
default :
|
||||
items = java.util.Collections.unmodifiableList(new java.util.ArrayList<String>(b.items));
|
||||
}
|
||||
this.items = items;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") ParentBuilder<?, ?> toBuilder() {
|
||||
return new ParentBuilderImpl().$fillValuesFrom(this);
|
||||
}
|
||||
public static @java.lang.SuppressWarnings("all") ParentBuilder<?, ?> builder() {
|
||||
return new ParentBuilderImpl();
|
||||
}
|
||||
}
|
||||
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() {
|
||||
super();
|
||||
}
|
||||
protected @java.lang.Override @java.lang.SuppressWarnings("all") B $fillValuesFrom(final C instance) {
|
||||
super.$fillValuesFrom(instance);
|
||||
ChildBuilder.$fillValuesFromInstanceIntoBuilder(instance, this);
|
||||
return self();
|
||||
}
|
||||
private static @java.lang.SuppressWarnings("all") void $fillValuesFromInstanceIntoBuilder(final Child instance, final ChildBuilder<?, ?> b) {
|
||||
b.field3(instance.field3);
|
||||
}
|
||||
protected abstract @java.lang.Override @java.lang.SuppressWarnings("all") B self();
|
||||
public abstract @java.lang.Override @java.lang.SuppressWarnings("all") C build();
|
||||
public @java.lang.SuppressWarnings("all") B field3(final double field3) {
|
||||
this.field3 = field3;
|
||||
return self();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
|
||||
return (((("SuperBuilderBasicToBuilder.Child.ChildBuilder(super=" + super.toString()) + ", field3=") + this.field3) + ")");
|
||||
}
|
||||
}
|
||||
private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends ChildBuilder<Child, ChildBuilderImpl> {
|
||||
private ChildBuilderImpl() {
|
||||
super();
|
||||
}
|
||||
protected @java.lang.Override @java.lang.SuppressWarnings("all") ChildBuilderImpl self() {
|
||||
return this;
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") Child build() {
|
||||
return new Child(this);
|
||||
}
|
||||
}
|
||||
private double field3;
|
||||
protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder<?, ?> b) {
|
||||
super(b);
|
||||
this.field3 = b.field3;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") ChildBuilder<?, ?> toBuilder() {
|
||||
return new ChildBuilderImpl().$fillValuesFrom(this);
|
||||
}
|
||||
public static @java.lang.SuppressWarnings("all") ChildBuilder<?, ?> builder() {
|
||||
return new ChildBuilderImpl();
|
||||
}
|
||||
}
|
||||
public SuperBuilderBasicToBuilder() {
|
||||
super();
|
||||
}
|
||||
public static void test() {
|
||||
Child x = Child.builder().field3(0.0).field1(5).item("").build().toBuilder().build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
import java.util.List;
|
||||
public class SuperBuilderWithGenericsAndToBuilder {
|
||||
public static @lombok.experimental.SuperBuilder(toBuilder = true) class Parent<A> {
|
||||
public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder<A, C extends Parent<A>, B extends ParentBuilder<A, C, B>> {
|
||||
private @java.lang.SuppressWarnings("all") A field1;
|
||||
private @java.lang.SuppressWarnings("all") java.util.ArrayList<String> items;
|
||||
public ParentBuilder() {
|
||||
super();
|
||||
}
|
||||
protected @java.lang.SuppressWarnings("all") B $fillValuesFrom(final C instance) {
|
||||
ParentBuilder.$fillValuesFromInstanceIntoBuilder(instance, this);
|
||||
return self();
|
||||
}
|
||||
private static @java.lang.SuppressWarnings("all") <A>void $fillValuesFromInstanceIntoBuilder(final Parent<A> instance, final ParentBuilder<A, ?, ?> b) {
|
||||
b.field1(instance.field1);
|
||||
b.items(((instance.items == null) ? java.util.Collections.emptyList() : instance.items));
|
||||
}
|
||||
protected abstract @java.lang.SuppressWarnings("all") B self();
|
||||
public abstract @java.lang.SuppressWarnings("all") C build();
|
||||
public @java.lang.SuppressWarnings("all") B field1(final A field1) {
|
||||
this.field1 = field1;
|
||||
return self();
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") B item(final String item) {
|
||||
if ((this.items == null))
|
||||
this.items = new java.util.ArrayList<String>();
|
||||
this.items.add(item);
|
||||
return self();
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") B items(final java.util.Collection<? extends String> items) {
|
||||
if ((this.items == null))
|
||||
this.items = new java.util.ArrayList<String>();
|
||||
this.items.addAll(items);
|
||||
return self();
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") B clearItems() {
|
||||
if ((this.items != null))
|
||||
this.items.clear();
|
||||
return self();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
|
||||
return (((("SuperBuilderWithGenericsAndToBuilder.Parent.ParentBuilder(field1=" + this.field1) + ", items=") + this.items) + ")");
|
||||
}
|
||||
}
|
||||
private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl<A> extends ParentBuilder<A, Parent<A>, ParentBuilderImpl<A>> {
|
||||
private ParentBuilderImpl() {
|
||||
super();
|
||||
}
|
||||
protected @java.lang.Override @java.lang.SuppressWarnings("all") ParentBuilderImpl<A> self() {
|
||||
return this;
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") Parent<A> build() {
|
||||
return new Parent<A>(this);
|
||||
}
|
||||
}
|
||||
A field1;
|
||||
@lombok.Singular List<String> items;
|
||||
protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder<A, ?, ?> b) {
|
||||
super();
|
||||
this.field1 = b.field1;
|
||||
java.util.List<String> items;
|
||||
switch (((b.items == null) ? 0 : b.items.size())) {
|
||||
case 0 :
|
||||
items = java.util.Collections.emptyList();
|
||||
break;
|
||||
case 1 :
|
||||
items = java.util.Collections.singletonList(b.items.get(0));
|
||||
break;
|
||||
default :
|
||||
items = java.util.Collections.unmodifiableList(new java.util.ArrayList<String>(b.items));
|
||||
}
|
||||
this.items = items;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") ParentBuilder<A, ?, ?> toBuilder() {
|
||||
return new ParentBuilderImpl<A>().$fillValuesFrom(this);
|
||||
}
|
||||
public static @java.lang.SuppressWarnings("all") <A>ParentBuilder<A, ?, ?> builder() {
|
||||
return new ParentBuilderImpl<A>();
|
||||
}
|
||||
}
|
||||
public static @lombok.experimental.SuperBuilder(toBuilder = true) class Child<A> extends Parent<A> {
|
||||
public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder<A, C extends Child<A>, B extends ChildBuilder<A, C, B>> extends Parent.ParentBuilder<A, C, B> {
|
||||
private @java.lang.SuppressWarnings("all") double field3;
|
||||
public ChildBuilder() {
|
||||
super();
|
||||
}
|
||||
protected @java.lang.Override @java.lang.SuppressWarnings("all") B $fillValuesFrom(final C instance) {
|
||||
super.$fillValuesFrom(instance);
|
||||
ChildBuilder.$fillValuesFromInstanceIntoBuilder(instance, this);
|
||||
return self();
|
||||
}
|
||||
private static @java.lang.SuppressWarnings("all") <A>void $fillValuesFromInstanceIntoBuilder(final Child<A> instance, final ChildBuilder<A, ?, ?> b) {
|
||||
b.field3(instance.field3);
|
||||
}
|
||||
protected abstract @java.lang.Override @java.lang.SuppressWarnings("all") B self();
|
||||
public abstract @java.lang.Override @java.lang.SuppressWarnings("all") C build();
|
||||
public @java.lang.SuppressWarnings("all") B field3(final double field3) {
|
||||
this.field3 = field3;
|
||||
return self();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
|
||||
return (((("SuperBuilderWithGenericsAndToBuilder.Child.ChildBuilder(super=" + super.toString()) + ", field3=") + this.field3) + ")");
|
||||
}
|
||||
}
|
||||
private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl<A> extends ChildBuilder<A, Child<A>, ChildBuilderImpl<A>> {
|
||||
private ChildBuilderImpl() {
|
||||
super();
|
||||
}
|
||||
protected @java.lang.Override @java.lang.SuppressWarnings("all") ChildBuilderImpl<A> self() {
|
||||
return this;
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") Child<A> build() {
|
||||
return new Child<A>(this);
|
||||
}
|
||||
}
|
||||
double field3;
|
||||
protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder<A, ?, ?> b) {
|
||||
super(b);
|
||||
this.field3 = b.field3;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") ChildBuilder<A, ?, ?> toBuilder() {
|
||||
return new ChildBuilderImpl<A>().$fillValuesFrom(this);
|
||||
}
|
||||
public static @java.lang.SuppressWarnings("all") <A>ChildBuilder<A, ?, ?> builder() {
|
||||
return new ChildBuilderImpl<A>();
|
||||
}
|
||||
}
|
||||
public SuperBuilderWithGenericsAndToBuilder() {
|
||||
super();
|
||||
}
|
||||
public static void test() {
|
||||
Child<Integer> x = Child.<Integer>builder().field3(0.0).field1(5).item("").build().toBuilder().build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
public class SuperBuilderAbstractToBuilder {
|
||||
@lombok.experimental.SuperBuilder(toBuilder = true)
|
||||
public static class Parent {
|
||||
int parentField;
|
||||
}
|
||||
|
||||
@lombok.experimental.SuperBuilder(toBuilder = true)
|
||||
public abstract static class Child extends Parent {
|
||||
double childField;
|
||||
}
|
||||
|
||||
@lombok.experimental.SuperBuilder(toBuilder = true)
|
||||
public static class GrandChild extends Child {
|
||||
String grandChildField;
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
GrandChild x = GrandChild.builder().grandChildField("").parentField(5).childField(2.5).build().toBuilder().build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import java.util.List;
|
||||
|
||||
public class SuperBuilderBasicToBuilder {
|
||||
@lombok.experimental.SuperBuilder(toBuilder=true)
|
||||
public static class Parent {
|
||||
private int field1;
|
||||
@lombok.Builder.ObtainVia(field="field1")
|
||||
int obtainViaField;
|
||||
@lombok.Builder.ObtainVia(method="method")
|
||||
int obtainViaMethod;
|
||||
@lombok.Builder.ObtainVia(method = "staticMethod", isStatic = true)
|
||||
String obtainViaStaticMethod;
|
||||
@lombok.Singular List<String> items;
|
||||
|
||||
private int method() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
private static String staticMethod(Parent instance) {
|
||||
return "staticMethod";
|
||||
}
|
||||
}
|
||||
|
||||
@lombok.experimental.SuperBuilder(toBuilder=true)
|
||||
public static class Child extends Parent {
|
||||
private double field3;
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
Child x = Child.builder().field3(0.0).field1(5).item("").build().toBuilder().build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import java.util.List;
|
||||
|
||||
public class SuperBuilderWithGenericsAndToBuilder {
|
||||
@lombok.experimental.SuperBuilder(toBuilder = true)
|
||||
public static class Parent<A> {
|
||||
A field1;
|
||||
@lombok.Singular List<String> items;
|
||||
}
|
||||
|
||||
@lombok.experimental.SuperBuilder(toBuilder = true)
|
||||
public static class Child<A> extends Parent<A> {
|
||||
double field3;
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
Child<Integer> x = Child.<Integer>builder().field3(0.0).field1(5).item("").build().toBuilder().build();
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,8 @@
|
||||
<code>@SuperBuilder</code> generates a private constructor on the class that takes a builder instance as a parameter. This constructor sets the fields of the new instance to the values from the builder.
|
||||
</p><p>
|
||||
<code>@SuperBuilder</code> is not compatible with <code>@Builder</code>.
|
||||
</p><p>
|
||||
You can use <code>@SuperBuilder(toBuilder = true)</code> to also generate an instance method in your class called <code>toBuilder()</code>; it creates a new builder that starts out with all the values of this instance. You can put the <code>@Builder.ObtainVia</code> annotation on the fields to indicate alternative means by which the value for that field/parameter is obtained from this instance. For example, you can specify a method to be invoked: <code>@Builder.ObtainVia(method = "calculateFoo")</code>.
|
||||
</p><p>
|
||||
To ensure type-safety, <code>@SuperBuilder</code> generates two inner builder classes for each annotated class, one abstract and one concrete class named <code><em>Foobar</em>Builder</code> and <code><em>Foobar</em>BuilderImpl</code> (where <em>Foobar</em> is the name of the annotated class).
|
||||
</p><p>
|
||||
@@ -31,10 +33,12 @@
|
||||
The <em>build()</em> method's name (default: <code>"build"</code>)
|
||||
</li><li>
|
||||
The <em>builder()</em> method's name (default: <code>"builder"</code>)
|
||||
</li><li>
|
||||
If you want <code>toBuilder()</code> (default: no)
|
||||
</li>
|
||||
</ul>
|
||||
Example usage where all options are changed from their defaults:<br />
|
||||
<code>@SuperBuilder(buildMethodName = "execute", builderMethodName = "helloWorld")</code><br />
|
||||
<code>@SuperBuilder(buildMethodName = "execute", builderMethodName = "helloWorld", toBuilder = true)</code><br />
|
||||
</p>
|
||||
</@f.overview>
|
||||
|
||||
|
||||
Reference in new issue
Block a user