mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-14 12:16:49 +00:00
Merge branch 'janrieke-superBuilder'
This commit is contained in:
commit
5dea27f56f
47 files changed
+3517
-205
No files matched your search
@@ -7,6 +7,7 @@ DaveLaw <project.lombok@apconsult.de>
|
||||
Dave Brosius <dbrosius@mebigfatguy.com>
|
||||
Dawid Rusin <dawidrusin90@gmail.com>
|
||||
Enrique da Costa Cambio <enrique.dacostacambio@gmail.com>
|
||||
Jan Rieke <it@janrieke.de>
|
||||
Jappe van der Hel <jappe.vanderhel@gmail.com>
|
||||
Kevin Chirls <kchirls@users.noreply.github.com>
|
||||
Liu DongMiao <liudongmiao@gmail.com>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2017 The Project Lombok Authors.
|
||||
* Copyright (C) 2013-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
|
||||
@@ -55,8 +55,8 @@ import java.lang.annotation.Target;
|
||||
*
|
||||
* <pre>
|
||||
* @Builder
|
||||
* class Example {
|
||||
* private int foo;
|
||||
* class Example<T> {
|
||||
* private T foo;
|
||||
* private final String bar;
|
||||
* }
|
||||
* </pre>
|
||||
@@ -103,6 +103,8 @@ import java.lang.annotation.Target;
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @see Singular
|
||||
*/
|
||||
@Target({TYPE, METHOD, CONSTRUCTOR})
|
||||
@Retention(SOURCE)
|
||||
|
||||
@@ -544,6 +544,15 @@ public class ConfigurationKeys {
|
||||
*/
|
||||
public static final ConfigurationKey<FlagUsageType> WITHER_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.wither.flagUsage", "Emit a warning or error if @Wither is used.") {};
|
||||
|
||||
// ----- SuperBuilder -----
|
||||
|
||||
/**
|
||||
* lombok configuration: {@code lombok.superBuilder.flagUsage} = {@code WARNING} | {@code ERROR}.
|
||||
*
|
||||
* If set, <em>any</em> usage of {@code @SuperBuilder} results in a warning / error.
|
||||
*/
|
||||
public static final ConfigurationKey<FlagUsageType> SUPERBUILDER_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.superBuilder.flagUsage", "Emit a warning or error if @SuperBuilder is used.") {};
|
||||
|
||||
// ----- Configuration System -----
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2017 The Project Lombok Authors.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -45,6 +45,9 @@ 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.QualifiedTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Reference;
|
||||
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.ThisReference;
|
||||
@@ -53,6 +56,7 @@ import org.eclipse.jdt.internal.compiler.ast.Wildcard;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
|
||||
|
||||
import lombok.core.LombokImmutableList;
|
||||
import lombok.core.SpiLoadUtil;
|
||||
@@ -60,6 +64,14 @@ import lombok.core.TypeLibrary;
|
||||
import lombok.eclipse.EclipseNode;
|
||||
|
||||
public class EclipseSingularsRecipes {
|
||||
public interface TypeReferenceMaker {
|
||||
TypeReference make();
|
||||
}
|
||||
|
||||
public interface StatementMaker {
|
||||
Statement make();
|
||||
}
|
||||
|
||||
private static final EclipseSingularsRecipes INSTANCE = new EclipseSingularsRecipes();
|
||||
private final Map<String, EclipseSingularizer> singularizers = new HashMap<String, EclipseSingularizer>();
|
||||
private final TypeLibrary singularizableTypes = new TypeLibrary();
|
||||
@@ -215,8 +227,36 @@ public class EclipseSingularsRecipes {
|
||||
}
|
||||
|
||||
public abstract List<EclipseNode> generateFields(SingularData data, EclipseNode builderType);
|
||||
public abstract void generateMethods(SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, boolean chain);
|
||||
public abstract void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName);
|
||||
|
||||
/**
|
||||
* Generates the singular, plural, and clear methods for the given {@link SingularData}.
|
||||
* Uses the given {@code builderType} as return type if {@code chain == true}, {@code void} otherwise.
|
||||
* If you need more control over the return type and value, use
|
||||
* {@link #generateMethods(SingularData, boolean, EclipseNode, boolean, TypeReferenceMaker, StatementMaker)}.
|
||||
*/
|
||||
public void generateMethods(SingularData data, boolean deprecate, final EclipseNode builderType, boolean fluent, final boolean chain) {
|
||||
TypeReferenceMaker returnTypeMaker = new TypeReferenceMaker() {
|
||||
@Override public TypeReference make() {
|
||||
return chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0);
|
||||
}
|
||||
};
|
||||
|
||||
StatementMaker returnStatementMaker = new StatementMaker() {
|
||||
@Override public ReturnStatement make() {
|
||||
return chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null;
|
||||
}
|
||||
};
|
||||
|
||||
generateMethods(data, deprecate, builderType, fluent, returnTypeMaker, returnStatementMaker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the singular, plural, and clear methods for the given {@link SingularData}.
|
||||
* Uses the given {@code returnTypeMaker} and {@code returnStatementMaker} for the generated methods.
|
||||
*/
|
||||
public abstract void generateMethods(SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, TypeReferenceMaker returnTypeMaker, StatementMaker returnStatementMaker);
|
||||
|
||||
public abstract void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName, String builderVariable);
|
||||
|
||||
public boolean requiresCleaning() {
|
||||
try {
|
||||
@@ -307,16 +347,16 @@ public class EclipseSingularsRecipes {
|
||||
private static final char[] SIZE_TEXT = new char[] {'s', 'i', 'z', 'e'};
|
||||
|
||||
/** Generates 'this.<em>name</em>.size()' as an expression; if nullGuard is true, it's this.name == null ? 0 : this.name.size(). */
|
||||
protected Expression getSize(EclipseNode builderType, char[] name, boolean nullGuard) {
|
||||
protected Expression getSize(EclipseNode builderType, char[] name, boolean nullGuard, String builderVariable) {
|
||||
MessageSend invoke = new MessageSend();
|
||||
ThisReference thisRef = new ThisReference(0, 0);
|
||||
Reference thisRef = getBuilderReference(builderVariable);
|
||||
FieldReference thisDotName = new FieldReference(name, 0L);
|
||||
thisDotName.receiver = thisRef;
|
||||
invoke.receiver = thisDotName;
|
||||
invoke.selector = SIZE_TEXT;
|
||||
if (!nullGuard) return invoke;
|
||||
|
||||
ThisReference cdnThisRef = new ThisReference(0, 0);
|
||||
Reference cdnThisRef = getBuilderReference(builderVariable);
|
||||
FieldReference cdnThisDotName = new FieldReference(name, 0L);
|
||||
cdnThisDotName.receiver = cdnThisRef;
|
||||
NullLiteral nullLiteral = new NullLiteral(0, 0);
|
||||
@@ -345,5 +385,14 @@ public class EclipseSingularsRecipes {
|
||||
|
||||
return new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, NULL_POSS);
|
||||
}
|
||||
|
||||
/** @return a {@code SingleNameReference} to the builder in the variable <code>builderVariable</code>. If {@ code builderVariable == "this"}, a {@code ThisReference} is returned. */
|
||||
protected static Reference getBuilderReference(String builderVariable) {
|
||||
if ("this".equals(builderVariable)) {
|
||||
return new ThisReference(0, 0);
|
||||
} else {
|
||||
return new SingleNameReference(builderVariable.toCharArray(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -573,7 +573,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
|
||||
bfd.singularData.getSingularizer().appendBuildCode(bfd.singularData, type, statements, bfd.name);
|
||||
bfd.singularData.getSingularizer().appendBuildCode(bfd.singularData, type, statements, bfd.name, "this");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -644,7 +644,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
return trs;
|
||||
}
|
||||
|
||||
public MethodDeclaration generateDefaultProvider(char[] methodName, TypeParameter[] typeParameters, EclipseNode fieldNode, ASTNode source) {
|
||||
public static MethodDeclaration generateDefaultProvider(char[] methodName, TypeParameter[] typeParameters, EclipseNode fieldNode, ASTNode source) {
|
||||
int pS = source.sourceStart, pE = source.sourceEnd;
|
||||
|
||||
MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) fieldNode.top().get()).compilationResult);
|
||||
|
||||
@@ -31,6 +31,7 @@ import lombok.core.AnnotationValues;
|
||||
import lombok.core.HandlerPriority;
|
||||
import lombok.eclipse.EclipseAnnotationHandler;
|
||||
import lombok.eclipse.EclipseNode;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
@ProviderFor(EclipseAnnotationHandler.class)
|
||||
@HandlerPriority(-1025) //HandleBuilder's level, minus one.
|
||||
@@ -39,8 +40,9 @@ public class HandleBuilderDefault extends EclipseAnnotationHandler<Builder.Defau
|
||||
EclipseNode annotatedField = annotationNode.up();
|
||||
if (annotatedField.getKind() != Kind.FIELD) return;
|
||||
EclipseNode classWithAnnotatedField = annotatedField.up();
|
||||
if (!hasAnnotation(Builder.class, classWithAnnotatedField) && !hasAnnotation("lombok.experimental.Builder", classWithAnnotatedField)) {
|
||||
annotationNode.addWarning("@Builder.Default requires @Builder on the class for it to mean anything.");
|
||||
if (!hasAnnotation(Builder.class, classWithAnnotatedField) && !hasAnnotation("lombok.experimental.Builder", classWithAnnotatedField)
|
||||
&& !hasAnnotation(SuperBuilder.class, classWithAnnotatedField)) {
|
||||
annotationNode.addWarning("@Builder.Default requires @Builder or @SuperBuilder on the class for it to mean anything.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -309,7 +309,6 @@ public class HandleConstructor {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static final char[][] JAVA_BEANS_CONSTRUCTORPROPERTIES = new char[][] { "java".toCharArray(), "beans".toCharArray(), "ConstructorProperties".toCharArray() };
|
||||
public static Annotation[] createConstructorProperties(ASTNode source, Collection<EclipseNode> fields) {
|
||||
|
||||
@@ -116,7 +116,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> {
|
||||
createSetterForField(level, fieldNode, sourceNode, false, onMethod, onParam);
|
||||
}
|
||||
|
||||
public void handle(AnnotationValues<Setter> annotation, Annotation ast, EclipseNode annotationNode) {
|
||||
@Override public void handle(AnnotationValues<Setter> annotation, Annotation ast, EclipseNode annotationNode) {
|
||||
handleFlagUsage(annotationNode, ConfigurationKeys.SETTER_FLAG_USAGE, "@Setter");
|
||||
|
||||
EclipseNode node = annotationNode.up();
|
||||
@@ -187,22 +187,34 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> {
|
||||
MethodDeclaration method = createSetter((TypeDeclaration) fieldNode.up().get(), false, fieldNode, setterName, null, shouldReturnThis, modifier, sourceNode, onMethod, onParam);
|
||||
injectMethod(fieldNode.up(), method);
|
||||
}
|
||||
|
||||
|
||||
static MethodDeclaration createSetter(TypeDeclaration parent, boolean deprecate, EclipseNode fieldNode, String name, char[] booleanFieldToSet, boolean shouldReturnThis, int modifier, EclipseNode sourceNode, List<Annotation> onMethod, List<Annotation> onParam) {
|
||||
ASTNode source = sourceNode.get();
|
||||
int pS = source.sourceStart, pE = source.sourceEnd;
|
||||
|
||||
TypeReference returnType = null;
|
||||
ReturnStatement returnThis = null;
|
||||
if (shouldReturnThis) {
|
||||
returnType = cloneSelfType(fieldNode, source);
|
||||
ThisReference thisRef = new ThisReference(pS, pE);
|
||||
returnThis = new ReturnStatement(thisRef, pS, pE);
|
||||
}
|
||||
|
||||
return createSetter(parent, deprecate, fieldNode, name, booleanFieldToSet, returnType, returnThis, modifier, sourceNode, onMethod, onParam);
|
||||
}
|
||||
|
||||
static MethodDeclaration createSetter(TypeDeclaration parent, boolean deprecate, EclipseNode fieldNode, String name, char[] booleanFieldToSet, TypeReference returnType, Statement returnStatement, int modifier, EclipseNode sourceNode, List<Annotation> onMethod, List<Annotation> onParam) {
|
||||
FieldDeclaration field = (FieldDeclaration) fieldNode.get();
|
||||
ASTNode source = sourceNode.get();
|
||||
int pS = source.sourceStart, pE = source.sourceEnd;
|
||||
long p = (long)pS << 32 | pE;
|
||||
MethodDeclaration method = new MethodDeclaration(parent.compilationResult);
|
||||
method.modifiers = modifier;
|
||||
if (shouldReturnThis) {
|
||||
method.returnType = cloneSelfType(fieldNode, source);
|
||||
}
|
||||
|
||||
if (method.returnType == null) {
|
||||
if (returnType != null) {
|
||||
method.returnType = returnType;
|
||||
} else {
|
||||
method.returnType = TypeReference.baseTypeReference(TypeIds.T_void, 0);
|
||||
method.returnType.sourceStart = pS; method.returnType.sourceEnd = pE;
|
||||
shouldReturnThis = false;
|
||||
}
|
||||
Annotation[] deprecated = null;
|
||||
if (isFieldDeprecated(fieldNode) || deprecate) {
|
||||
@@ -239,10 +251,8 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> {
|
||||
statements.add(new Assignment(new SingleNameReference(booleanFieldToSet, p), new TrueLiteral(pS, pE), pE));
|
||||
}
|
||||
|
||||
if (shouldReturnThis) {
|
||||
ThisReference thisRef = new ThisReference(pS, pE);
|
||||
ReturnStatement returnThis = new ReturnStatement(thisRef, pS, pE);
|
||||
statements.add(returnThis);
|
||||
if (returnType != null && returnStatement != null) {
|
||||
statements.add(returnStatement);
|
||||
}
|
||||
method.statements = statements.toArray(new Statement[0]);
|
||||
param.annotations = copyAnnotations(source, nonNulls, nullables, onParam.toArray(new Annotation[0]));
|
||||
|
||||
@@ -0,0 +1,836 @@
|
||||
/*
|
||||
* Copyright (C) 2013-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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package lombok.eclipse.handlers;
|
||||
|
||||
import static lombok.core.handlers.HandlerUtil.*;
|
||||
import static lombok.eclipse.Eclipse.*;
|
||||
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
|
||||
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
|
||||
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.ConstructorDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Expression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FieldReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.IfStatement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
|
||||
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
|
||||
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.ThisReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
|
||||
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Wildcard;
|
||||
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
|
||||
import org.mangosdk.spi.ProviderFor;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Builder;
|
||||
import lombok.Builder.ObtainVia;
|
||||
import lombok.ConfigurationKeys;
|
||||
import lombok.Singular;
|
||||
import lombok.ToString;
|
||||
import lombok.core.AST.Kind;
|
||||
import lombok.core.handlers.InclusionExclusionUtils.Included;
|
||||
import lombok.core.AnnotationValues;
|
||||
import lombok.core.HandlerPriority;
|
||||
import lombok.eclipse.Eclipse;
|
||||
import lombok.eclipse.EclipseAnnotationHandler;
|
||||
import lombok.eclipse.EclipseNode;
|
||||
import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult;
|
||||
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.experimental.NonFinal;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
@ProviderFor(EclipseAnnotationHandler.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 EclipseAnnotationHandler<SuperBuilder> {
|
||||
private static final char[] CLEAN_FIELD_NAME = "$lombokUnclean".toCharArray();
|
||||
private static final char[] CLEAN_METHOD_NAME = "$lombokClean".toCharArray();
|
||||
private static final char[] SET_PREFIX = "$set".toCharArray();
|
||||
private static final char[] SELF_METHOD_NAME = "self".toCharArray();
|
||||
|
||||
private static final AbstractMethodDeclaration[] EMPTY_METHODS = {};
|
||||
|
||||
private static class BuilderFieldData {
|
||||
TypeReference type;
|
||||
char[] rawName;
|
||||
char[] name;
|
||||
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();
|
||||
|
||||
String builderMethodName = builderInstance.builderMethodName();
|
||||
String buildMethodName = builderInstance.buildMethodName();
|
||||
|
||||
if (builderMethodName == null) builderMethodName = "builder";
|
||||
if (buildMethodName == null) buildMethodName = "build";
|
||||
|
||||
if (!checkName("builderMethodName", builderMethodName, annotationNode)) return;
|
||||
if (!checkName("buildMethodName", buildMethodName, annotationNode)) return;
|
||||
|
||||
EclipseNode tdParent = annotationNode.up();
|
||||
|
||||
java.util.List<BuilderFieldData> builderFields = new ArrayList<BuilderFieldData>();
|
||||
TypeReference returnType;
|
||||
TypeParameter[] typeParams;
|
||||
|
||||
boolean addCleaning = false;
|
||||
|
||||
if (!(tdParent.get() instanceof TypeDeclaration)) {
|
||||
annotationNode.addError("@SuperBuilder is only supported on types.");
|
||||
return;
|
||||
}
|
||||
TypeDeclaration td = (TypeDeclaration) tdParent.get();
|
||||
|
||||
// Gather all fields of the class that should be set by the builder.
|
||||
List<EclipseNode> allFields = new ArrayList<EclipseNode>();
|
||||
boolean valuePresent = (hasAnnotation(lombok.Value.class, tdParent) || hasAnnotation("lombok.experimental.Value", tdParent));
|
||||
for (EclipseNode fieldNode : HandleConstructor.findAllFields(tdParent, true)) {
|
||||
FieldDeclaration fd = (FieldDeclaration) fieldNode.get();
|
||||
EclipseNode isDefault = findAnnotation(Builder.Default.class, fieldNode);
|
||||
boolean isFinal = ((fd.modifiers & ClassFileConstants.AccFinal) != 0) || (valuePresent && !hasAnnotation(NonFinal.class, fieldNode));
|
||||
|
||||
BuilderFieldData bfd = new BuilderFieldData();
|
||||
bfd.rawName = fieldNode.getName().toCharArray();
|
||||
bfd.name = removePrefixFromField(fieldNode);
|
||||
bfd.type = fd.type;
|
||||
bfd.singularData = getSingularData(fieldNode, ast);
|
||||
bfd.originalFieldNode = fieldNode;
|
||||
|
||||
if (bfd.singularData != null && isDefault != null) {
|
||||
isDefault.addError("@Builder.Default and @Singular cannot be mixed.");
|
||||
isDefault = null;
|
||||
}
|
||||
|
||||
if (fd.initialization == null && isDefault != null) {
|
||||
isDefault.addWarning("@Builder.Default requires an initializing expression (' = something;').");
|
||||
isDefault = null;
|
||||
}
|
||||
|
||||
if (fd.initialization != null && isDefault == null) {
|
||||
if (isFinal) {
|
||||
continue;
|
||||
}
|
||||
fieldNode.addWarning("@Builder will ignore the initializing expression entirely. If you want the initializing expression to serve as default, add @Builder.Default. If it is not supposed to be settable during building, make the field final.");
|
||||
}
|
||||
|
||||
if (isDefault != null) {
|
||||
bfd.nameOfSetFlag = prefixWith(bfd.name, SET_PREFIX);
|
||||
// The @Builder annotation removes the initializing expression on the field and moves
|
||||
// it to a method called "$default$FIELDNAME". This method is then called upon building.
|
||||
// We do NOT do this, because this is unexpected and may lead to bugs when using other
|
||||
// constructors (see, e.g., issue #1347).
|
||||
// Instead, we keep the init expression and only set a new value in the builder-based
|
||||
// constructor if it was set in the builder. Drawback is that the init expression is
|
||||
// always executed, even if it was unnecessary because its value is overwritten by the
|
||||
// builder.
|
||||
// TODO: Once the issue is resolved in @Builder, we can adapt the solution here.
|
||||
}
|
||||
addObtainVia(bfd, fieldNode);
|
||||
builderFields.add(bfd);
|
||||
allFields.add(fieldNode);
|
||||
}
|
||||
|
||||
// Set the names of the builder classes.
|
||||
String builderClassName = String.valueOf(td.name) + "Builder";
|
||||
String builderImplClassName = builderClassName + "Impl";
|
||||
|
||||
typeParams = td.typeParameters != null ? td.typeParameters : new TypeParameter[0];
|
||||
returnType = namePlusTypeParamsToTypeReference(td.name, typeParams, p);
|
||||
|
||||
// <C, B> are the generics for our builder.
|
||||
String classGenericName = "C";
|
||||
String builderGenericName = "B";
|
||||
// If these generics' names collide with any generics on the annotated class, modify them.
|
||||
// For instance, if there are generics <B, B2, C> on the annotated class, use "C2" and "B3" for our builder.
|
||||
java.util.List<String> typeParamStrings = new ArrayList<String>();
|
||||
for (TypeParameter typeParam : typeParams) typeParamStrings.add(typeParam.toString());
|
||||
classGenericName = generateNonclashingNameFor(classGenericName, typeParamStrings);
|
||||
builderGenericName = generateNonclashingNameFor(builderGenericName, typeParamStrings);
|
||||
|
||||
TypeReference extendsClause = td.superclass;
|
||||
TypeReference superclassBuilderClass = null;
|
||||
TypeReference[] typeArguments = new TypeReference[] {
|
||||
new SingleTypeReference(classGenericName.toCharArray(), 0),
|
||||
new SingleTypeReference(builderGenericName.toCharArray(), 0)
|
||||
};
|
||||
if (extendsClause instanceof QualifiedTypeReference) {
|
||||
QualifiedTypeReference qualifiedTypeReference = (QualifiedTypeReference)extendsClause;
|
||||
String superclassClassName = String.valueOf(qualifiedTypeReference.getLastToken());
|
||||
String superclassBuilderClassName = superclassClassName + "Builder";
|
||||
|
||||
char[][] tokens = Arrays.copyOf(qualifiedTypeReference.tokens, qualifiedTypeReference.tokens.length + 1);
|
||||
tokens[tokens.length] = superclassBuilderClassName.toCharArray();
|
||||
long[] poss = new long[tokens.length];
|
||||
Arrays.fill(poss, p);
|
||||
|
||||
TypeReference[] superclassTypeArgs = getTypeParametersFrom(extendsClause);
|
||||
|
||||
// Every token may potentially have type args. Here, we only have
|
||||
// type args for the last token, the superclass' builder.
|
||||
TypeReference[][] typeArgsForTokens = new TypeReference[tokens.length][];
|
||||
typeArgsForTokens[typeArgsForTokens.length-1] = mergeTypeReferences(superclassTypeArgs, typeArguments);
|
||||
|
||||
superclassBuilderClass = new ParameterizedQualifiedTypeReference(tokens, typeArgsForTokens, 0, poss);
|
||||
} else if (extendsClause != null) {
|
||||
String superClass = String.valueOf(extendsClause.getTypeName()[0]);
|
||||
String superclassBuilderClassName = superClass + "Builder";
|
||||
|
||||
char[][] tokens = new char[][] {superClass.toCharArray(), superclassBuilderClassName.toCharArray()};
|
||||
long[] poss = new long[tokens.length];
|
||||
Arrays.fill(poss, p);
|
||||
|
||||
TypeReference[] superclassTypeArgs = getTypeParametersFrom(extendsClause);
|
||||
|
||||
// Every token may potentially have type args. Here, we only have
|
||||
// type args for the last token, the superclass' builder.
|
||||
TypeReference[][] typeArgsForTokens = new TypeReference[tokens.length][];
|
||||
typeArgsForTokens[typeArgsForTokens.length-1] = mergeTypeReferences(superclassTypeArgs, typeArguments);
|
||||
|
||||
superclassBuilderClass = new ParameterizedQualifiedTypeReference(tokens, typeArgsForTokens, 0, poss);
|
||||
}
|
||||
// If there is no superclass, superclassBuilderClassExpression is still == null at this point.
|
||||
// You can use it to check whether to inherit or not.
|
||||
|
||||
generateBuilderBasedConstructor(tdParent, typeParams, builderFields, annotationNode, builderClassName,
|
||||
superclassBuilderClass != null);
|
||||
|
||||
// Create the abstract builder class.
|
||||
EclipseNode builderType = findInnerClass(tdParent, builderClassName);
|
||||
if (builderType == null) {
|
||||
builderType = generateBuilderAbstractClass(tdParent, builderClassName, superclassBuilderClass,
|
||||
typeParams, ast, classGenericName, builderGenericName);
|
||||
} else {
|
||||
annotationNode.addError("@SuperBuilder does not support customized builders. Use @Builder instead.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check validity of @ObtainVia fields, and add check if adding cleaning for @Singular is necessary.
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
|
||||
if (bfd.singularData.getSingularizer().requiresCleaning()) {
|
||||
addCleaning = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bfd.obtainVia != null) {
|
||||
if (bfd.obtainVia.field().isEmpty() == bfd.obtainVia.method().isEmpty()) {
|
||||
bfd.obtainViaNode.addError("The syntax is either @ObtainVia(field = \"fieldName\") or @ObtainVia(method = \"methodName\").");
|
||||
return;
|
||||
}
|
||||
if (bfd.obtainVia.method().isEmpty() && bfd.obtainVia.isStatic()) {
|
||||
bfd.obtainViaNode.addError("@ObtainVia(isStatic = true) is not valid unless 'method' has been set.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the fields in the abstract builder class that hold the values for the instance.
|
||||
generateBuilderFields(builderType, builderFields, ast);
|
||||
if (addCleaning) {
|
||||
FieldDeclaration cleanDecl = new FieldDeclaration(CLEAN_FIELD_NAME, 0, -1);
|
||||
cleanDecl.declarationSourceEnd = -1;
|
||||
cleanDecl.modifiers = ClassFileConstants.AccPrivate;
|
||||
cleanDecl.type = TypeReference.baseTypeReference(TypeIds.T_boolean, 0);
|
||||
injectFieldAndMarkGenerated(builderType, cleanDecl);
|
||||
}
|
||||
|
||||
// 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));
|
||||
|
||||
// Create the setter methods in the abstract builder.
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
generateSetterMethodsForBuilder(builderType, bfd, annotationNode, builderGenericName);
|
||||
}
|
||||
|
||||
// Create the toString() method for the abstract builder.
|
||||
if (methodExists("toString", builderType, 0) == MemberExistsResult.NOT_EXISTS) {
|
||||
List<Included<EclipseNode, ToString.Include>> fieldNodes = new ArrayList<Included<EclipseNode, ToString.Include>>();
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
for (EclipseNode f : bfd.createdFields) {
|
||||
fieldNodes.add(new Included<EclipseNode, ToString.Include>(f, null, true));
|
||||
}
|
||||
}
|
||||
// Let toString() call super.toString() if there is a superclass, so that it also shows fields from the superclass' builder.
|
||||
MethodDeclaration md = HandleToString.createToString(builderType, fieldNodes, true, superclassBuilderClass != null, ast, FieldAccess.ALWAYS_FIELD);
|
||||
if (md != null) {
|
||||
injectMethod(builderType, md);
|
||||
}
|
||||
}
|
||||
|
||||
if (addCleaning) injectMethod(builderType, generateCleanMethod(builderFields, builderType, ast));
|
||||
|
||||
if ((td.modifiers & ClassFileConstants.AccAbstract) != 0) {
|
||||
// Only non-abstract classes get the Builder implementation.
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the builder implementation class.
|
||||
EclipseNode builderImplType = findInnerClass(tdParent, builderImplClassName);
|
||||
if (builderImplType == null) {
|
||||
builderImplType = generateBuilderImplClass(tdParent, builderImplClassName, builderClassName, typeParams, ast);
|
||||
} else {
|
||||
annotationNode.addError("@SuperBuilder does not support customized builders. Use @Builder instead.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the self() and build() methods in the BuilderImpl.
|
||||
injectMethod(builderImplType, generateSelfMethod(builderImplType));
|
||||
injectMethod(builderImplType, generateBuildMethod(tdParent, buildMethodName, returnType, ast));
|
||||
|
||||
// Add the builder() method to the annotated class.
|
||||
if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) {
|
||||
MethodDeclaration md = generateBuilderMethod(builderMethodName, builderClassName, builderImplClassName, tdParent, typeParams, ast);
|
||||
if (md != null) injectMethod(tdParent, md);
|
||||
}
|
||||
}
|
||||
|
||||
private EclipseNode generateBuilderAbstractClass(EclipseNode tdParent, String builderClass,
|
||||
TypeReference superclassBuilderClass, TypeParameter[] typeParams,
|
||||
ASTNode source, String classGenericName, String builderGenericName) {
|
||||
|
||||
TypeDeclaration parent = (TypeDeclaration) tdParent.get();
|
||||
TypeDeclaration builder = new TypeDeclaration(parent.compilationResult);
|
||||
builder.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
builder.modifiers |= ClassFileConstants.AccPublic | ClassFileConstants.AccStatic | ClassFileConstants.AccAbstract;
|
||||
builder.name = builderClass.toCharArray();
|
||||
|
||||
// Keep any type params of the annotated class.
|
||||
builder.typeParameters = Arrays.copyOf(copyTypeParams(typeParams, source), typeParams.length + 2);
|
||||
// Add builder-specific type params required for inheritable builders.
|
||||
// 1. The return type for the build() method, named "C", which extends the annotated class.
|
||||
TypeParameter o = new TypeParameter();
|
||||
o.name = classGenericName.toCharArray();
|
||||
o.type = cloneSelfType(tdParent, source);
|
||||
builder.typeParameters[builder.typeParameters.length - 2] = o;
|
||||
// 2. The return type for all setter methods, named "B", which extends this builder class.
|
||||
o = new TypeParameter();
|
||||
o.name = builderGenericName.toCharArray();
|
||||
TypeReference[] typerefs = appendBuilderTypeReferences(typeParams, classGenericName, builderGenericName);
|
||||
o.type = new ParameterizedSingleTypeReference(builderClass.toCharArray(), typerefs, 0, 0);
|
||||
builder.typeParameters[builder.typeParameters.length - 1] = o;
|
||||
|
||||
builder.superclass = copyType(superclassBuilderClass, source);
|
||||
|
||||
builder.createDefaultConstructor(false, true);
|
||||
|
||||
builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null);
|
||||
return injectType(tdParent, builder);
|
||||
}
|
||||
|
||||
private EclipseNode generateBuilderImplClass(EclipseNode tdParent, String builderImplClass, String builderAbstractClass, TypeParameter[] typeParams, ASTNode source) {
|
||||
TypeDeclaration parent = (TypeDeclaration) tdParent.get();
|
||||
TypeDeclaration builder = new TypeDeclaration(parent.compilationResult);
|
||||
builder.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
builder.modifiers |= ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal;
|
||||
builder.name = builderImplClass.toCharArray();
|
||||
|
||||
// Add type params if there are any.
|
||||
if (typeParams != null && typeParams.length > 0) builder.typeParameters = copyTypeParams(typeParams, source);
|
||||
|
||||
if (builderAbstractClass != null) {
|
||||
// Extend the abstract builder.
|
||||
// 1. Add any type params of the annotated class.
|
||||
TypeReference[] typeArgs = new TypeReference[typeParams.length + 2];
|
||||
for (int i = 0; i < typeParams.length; i++) {
|
||||
typeArgs[i] = new SingleTypeReference(typeParams[i].name, 0);
|
||||
}
|
||||
// 2. The return type for the build() method (named "C" in the abstract builder), which is the annotated class.
|
||||
// 3. The return type for all setter methods (named "B" in the abstract builder), which is this builder class.
|
||||
typeArgs[typeArgs.length - 2] = cloneSelfType(tdParent, source);
|
||||
typeArgs[typeArgs.length - 1] = createTypeReferenceWithTypeParameters(builderImplClass, typeParams);
|
||||
builder.superclass = new ParameterizedSingleTypeReference(builderAbstractClass.toCharArray(), typeArgs, 0, 0);
|
||||
}
|
||||
|
||||
builder.createDefaultConstructor(false, true);
|
||||
|
||||
builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null);
|
||||
return injectType(tdParent, builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a constructor that has a builder as the only parameter.
|
||||
* The values from the builder are used to initialize the fields of new instances.
|
||||
*
|
||||
* @param typeNode
|
||||
* the type (with the {@code @Builder} annotation) for which a
|
||||
* constructor should be generated.
|
||||
* @param typeParams
|
||||
* @param builderFields a list of fields in the builder which should be assigned to new instances.
|
||||
* @param source the annotation (used for setting source code locations for the generated code).
|
||||
* @param callBuilderBasedSuperConstructor
|
||||
* If {@code true}, the constructor will explicitly call a super
|
||||
* constructor with the builder as argument. Requires
|
||||
* {@code builderClassAsParameter != null}.
|
||||
*/
|
||||
private void generateBuilderBasedConstructor(EclipseNode typeNode, TypeParameter[] typeParams, List<BuilderFieldData> builderFields,
|
||||
EclipseNode sourceNode, String builderClassName, boolean callBuilderBasedSuperConstructor) {
|
||||
|
||||
ASTNode source = sourceNode.get();
|
||||
|
||||
TypeDeclaration typeDeclaration = ((TypeDeclaration) typeNode.get());
|
||||
long p = (long) source.sourceStart << 32 | source.sourceEnd;
|
||||
|
||||
ConstructorDeclaration constructor = new ConstructorDeclaration(((CompilationUnitDeclaration) typeNode.top().get()).compilationResult);
|
||||
|
||||
constructor.modifiers = toEclipseModifier(AccessLevel.PROTECTED);
|
||||
constructor.selector = typeDeclaration.name;
|
||||
if (callBuilderBasedSuperConstructor) {
|
||||
constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.Super);
|
||||
constructor.constructorCall.arguments = new Expression[] {new SingleNameReference("b".toCharArray(), p)};
|
||||
} else {
|
||||
constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper);
|
||||
}
|
||||
constructor.constructorCall.sourceStart = source.sourceStart;
|
||||
constructor.constructorCall.sourceEnd = source.sourceEnd;
|
||||
constructor.thrownExceptions = null;
|
||||
constructor.typeParameters = null;
|
||||
constructor.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
constructor.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = source.sourceStart;
|
||||
constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = source.sourceEnd;
|
||||
|
||||
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)};
|
||||
|
||||
List<Statement> statements = new ArrayList<Statement>();
|
||||
List<Statement> nullChecks = new ArrayList<Statement>();
|
||||
|
||||
for (BuilderFieldData fieldNode : builderFields) {
|
||||
char[] fieldName = removePrefixFromField(fieldNode.originalFieldNode);
|
||||
FieldReference thisX = new FieldReference(fieldNode.rawName, p);
|
||||
int s = (int) (p >> 32);
|
||||
int e = (int) p;
|
||||
thisX.receiver = new ThisReference(s, e);
|
||||
|
||||
Expression assignmentExpr;
|
||||
if (fieldNode.singularData != null && fieldNode.singularData.getSingularizer() != null) {
|
||||
fieldNode.singularData.getSingularizer().appendBuildCode(fieldNode.singularData, typeNode, statements, fieldNode.name, "b");
|
||||
assignmentExpr = new SingleNameReference(fieldNode.name, p);
|
||||
} else {
|
||||
char[][] variableInBuilder = new char[][] {"b".toCharArray(), fieldName};
|
||||
long[] positions = new long[] {p, p};
|
||||
assignmentExpr = new QualifiedNameReference(variableInBuilder, positions, s, e);
|
||||
}
|
||||
Statement assignment = new Assignment(thisX, assignmentExpr, (int) p);
|
||||
|
||||
// In case of @Builder.Default, only set the value if it really was set in the builder.
|
||||
if (fieldNode.nameOfSetFlag != null) {
|
||||
char[][] variableInBuilder = new char[][] {"b".toCharArray(), fieldNode.nameOfSetFlag};
|
||||
long[] positions = new long[] {p, p};
|
||||
QualifiedNameReference builderRef = new QualifiedNameReference(variableInBuilder, positions, s, e);
|
||||
assignment = new IfStatement(builderRef, assignment, s, e);
|
||||
}
|
||||
statements.add(assignment);
|
||||
|
||||
Annotation[] nonNulls = findAnnotations((FieldDeclaration)fieldNode.originalFieldNode.get(), NON_NULL_PATTERN);
|
||||
if (nonNulls.length != 0) {
|
||||
Statement nullCheck = generateNullCheck((FieldDeclaration)fieldNode.originalFieldNode.get(), sourceNode);
|
||||
if (nullCheck != null) {
|
||||
nullChecks.add(nullCheck);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nullChecks.addAll(statements);
|
||||
constructor.statements = nullChecks.isEmpty() ? null : nullChecks.toArray(new Statement[nullChecks.size()]);
|
||||
|
||||
constructor.traverse(new SetGeneratedByVisitor(source), typeDeclaration.scope);
|
||||
|
||||
injectMethod(typeNode, constructor);
|
||||
}
|
||||
|
||||
private MethodDeclaration generateBuilderMethod(String builderMethodName, 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 = builderMethodName.toCharArray();
|
||||
out.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccStatic;
|
||||
out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
|
||||
// Add type params if there are any.
|
||||
if (typeParams != null && typeParams.length > 0) out.typeParameters = copyTypeParams(typeParams, source);
|
||||
|
||||
TypeReference[] wildcards = new TypeReference[] {new Wildcard(Wildcard.UNBOUND), new Wildcard(Wildcard.UNBOUND) };
|
||||
out.returnType = new ParameterizedSingleTypeReference(builderClassName.toCharArray(), mergeToTypeReferences(typeParams, wildcards), 0, p);
|
||||
|
||||
AllocationExpression invoke = new AllocationExpression();
|
||||
invoke.type = namePlusTypeParamsToTypeReference(builderImplClassName.toCharArray(), typeParams, p);
|
||||
out.statements = new Statement[] {new ReturnStatement(invoke, pS, pE)};
|
||||
|
||||
out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) type.get()).scope);
|
||||
return out;
|
||||
}
|
||||
|
||||
private MethodDeclaration generateAbstractSelfMethod(EclipseNode tdParent, boolean override, String builderGenericName) {
|
||||
MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult);
|
||||
out.selector = SELF_METHOD_NAME;
|
||||
out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
out.modifiers = ClassFileConstants.AccAbstract | ClassFileConstants.AccProtected | ExtraCompilerModifiers.AccSemicolonBody;
|
||||
if (override) out.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, tdParent.get())};
|
||||
out.returnType = new SingleTypeReference(builderGenericName.toCharArray(), 0);
|
||||
return out;
|
||||
}
|
||||
|
||||
private MethodDeclaration generateSelfMethod(EclipseNode builderImplType) {
|
||||
MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) builderImplType.top().get()).compilationResult);
|
||||
out.selector = SELF_METHOD_NAME;
|
||||
out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
out.modifiers = ClassFileConstants.AccProtected;
|
||||
out.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, builderImplType.get())};
|
||||
out.returnType = new SingleTypeReference(builderImplType.getName().toCharArray(), 0);
|
||||
out.statements = new Statement[] {new ReturnStatement(new ThisReference(0, 0), 0, 0)};
|
||||
return out;
|
||||
}
|
||||
|
||||
private MethodDeclaration generateAbstractBuildMethod(EclipseNode tdParent, String methodName, boolean override,
|
||||
String classGenericName, ASTNode source) {
|
||||
|
||||
MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult);
|
||||
out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
|
||||
out.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract | ExtraCompilerModifiers.AccSemicolonBody;
|
||||
out.selector = methodName.toCharArray();
|
||||
out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
out.returnType = new SingleTypeReference(classGenericName.toCharArray(), 0);
|
||||
if (override) out.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source)};
|
||||
out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null);
|
||||
return out;
|
||||
}
|
||||
|
||||
private MethodDeclaration generateBuildMethod(EclipseNode tdParent, String name, TypeReference returnType, ASTNode source) {
|
||||
MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult);
|
||||
out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
List<Statement> statements = new ArrayList<Statement>();
|
||||
|
||||
out.modifiers = ClassFileConstants.AccPublic;
|
||||
out.selector = name.toCharArray();
|
||||
out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
out.returnType = returnType;
|
||||
out.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source)};
|
||||
|
||||
AllocationExpression allocationStatement = new AllocationExpression();
|
||||
allocationStatement.type = copyType(out.returnType);
|
||||
// Use a constructor that only has this builder as parameter.
|
||||
allocationStatement.arguments = new Expression[] {new ThisReference(0, 0)};
|
||||
statements.add(new ReturnStatement(allocationStatement, 0, 0));
|
||||
out.statements = statements.isEmpty() ? null : statements.toArray(new Statement[statements.size()]);
|
||||
out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null);
|
||||
return out;
|
||||
}
|
||||
|
||||
private MethodDeclaration generateCleanMethod(List<BuilderFieldData> builderFields, EclipseNode builderType, ASTNode source) {
|
||||
List<Statement> statements = new ArrayList<Statement>();
|
||||
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
|
||||
bfd.singularData.getSingularizer().appendCleaningCode(bfd.singularData, builderType, statements);
|
||||
}
|
||||
}
|
||||
|
||||
FieldReference thisUnclean = new FieldReference(CLEAN_FIELD_NAME, 0);
|
||||
thisUnclean.receiver = new ThisReference(0, 0);
|
||||
statements.add(new Assignment(thisUnclean, new FalseLiteral(0, 0), 0));
|
||||
MethodDeclaration decl = new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult);
|
||||
decl.selector = CLEAN_METHOD_NAME;
|
||||
decl.modifiers = ClassFileConstants.AccPrivate;
|
||||
decl.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
decl.returnType = TypeReference.baseTypeReference(TypeIds.T_void, 0);
|
||||
decl.statements = statements.toArray(new Statement[0]);
|
||||
decl.traverse(new SetGeneratedByVisitor(source), (ClassScope) null);
|
||||
return decl;
|
||||
}
|
||||
|
||||
private void generateBuilderFields(EclipseNode builderType, List<BuilderFieldData> builderFields, ASTNode source) {
|
||||
List<EclipseNode> existing = new ArrayList<EclipseNode>();
|
||||
for (EclipseNode child : builderType.down()) {
|
||||
if (child.getKind() == Kind.FIELD) existing.add(child);
|
||||
}
|
||||
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
|
||||
bfd.createdFields.addAll(bfd.singularData.getSingularizer().generateFields(bfd.singularData, builderType));
|
||||
} else {
|
||||
EclipseNode field = null, setFlag = null;
|
||||
for (EclipseNode exists : existing) {
|
||||
char[] n = ((FieldDeclaration) exists.get()).name;
|
||||
if (Arrays.equals(n, bfd.name)) field = exists;
|
||||
if (bfd.nameOfSetFlag != null && Arrays.equals(n, bfd.nameOfSetFlag)) setFlag = exists;
|
||||
}
|
||||
|
||||
if (field == null) {
|
||||
FieldDeclaration fd = new FieldDeclaration(bfd.name, 0, 0);
|
||||
fd.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
fd.modifiers = ClassFileConstants.AccPrivate;
|
||||
fd.type = copyType(bfd.type);
|
||||
fd.traverse(new SetGeneratedByVisitor(source), (MethodScope) null);
|
||||
field = injectFieldAndMarkGenerated(builderType, fd);
|
||||
}
|
||||
if (setFlag == null && bfd.nameOfSetFlag != null) {
|
||||
FieldDeclaration fd = new FieldDeclaration(bfd.nameOfSetFlag, 0, 0);
|
||||
fd.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
fd.modifiers = ClassFileConstants.AccPrivate;
|
||||
fd.type = TypeReference.baseTypeReference(TypeIds.T_boolean, 0);
|
||||
fd.traverse(new SetGeneratedByVisitor(source), (MethodScope) null);
|
||||
injectFieldAndMarkGenerated(builderType, fd);
|
||||
}
|
||||
bfd.createdFields.add(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generateSetterMethodsForBuilder(EclipseNode builderType, BuilderFieldData bfd, EclipseNode sourceNode, final String builderGenericName) {
|
||||
boolean deprecate = isFieldDeprecated(bfd.originalFieldNode);
|
||||
|
||||
TypeReferenceMaker returnTypeMaker = new TypeReferenceMaker() {
|
||||
@Override public TypeReference make() {
|
||||
return new SingleTypeReference(builderGenericName.toCharArray(), 0);
|
||||
}
|
||||
};
|
||||
|
||||
StatementMaker returnStatementMaker = new StatementMaker() {
|
||||
@Override public ReturnStatement make() {
|
||||
MessageSend returnCall = new MessageSend();
|
||||
returnCall.receiver = ThisReference.implicitThis();
|
||||
returnCall.selector = SELF_METHOD_NAME;
|
||||
return new ReturnStatement(returnCall, 0, 0);
|
||||
}
|
||||
};
|
||||
|
||||
if (bfd.singularData == null || bfd.singularData.getSingularizer() == null) {
|
||||
generateSimpleSetterMethodForBuilder(builderType, deprecate, bfd.createdFields.get(0), bfd.nameOfSetFlag, returnTypeMaker.make(), returnStatementMaker.make(), sourceNode);
|
||||
} else {
|
||||
bfd.singularData.getSingularizer().generateMethods(bfd.singularData, deprecate, builderType, true, returnTypeMaker, returnStatementMaker);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateSimpleSetterMethodForBuilder(EclipseNode builderType, boolean deprecate, EclipseNode fieldNode, char[] nameOfSetFlag, TypeReference returnType, Statement returnStatement, EclipseNode sourceNode) {
|
||||
TypeDeclaration td = (TypeDeclaration) builderType.get();
|
||||
AbstractMethodDeclaration[] existing = td.methods;
|
||||
if (existing == null) existing = EMPTY_METHODS;
|
||||
int len = existing.length;
|
||||
FieldDeclaration fd = (FieldDeclaration) fieldNode.get();
|
||||
char[] name = fd.name;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (!(existing[i] instanceof MethodDeclaration)) continue;
|
||||
char[] existingName = existing[i].selector;
|
||||
if (Arrays.equals(name, existingName) && !isTolerate(fieldNode, existing[i])) return;
|
||||
}
|
||||
|
||||
String setterName = fieldNode.getName();
|
||||
|
||||
MethodDeclaration setter = HandleSetter.createSetter(td, deprecate, fieldNode, setterName, nameOfSetFlag, returnType, returnStatement, ClassFileConstants.AccPublic,
|
||||
sourceNode, Collections.<Annotation>emptyList(), Collections.<Annotation>emptyList());
|
||||
injectMethod(builderType, setter);
|
||||
}
|
||||
|
||||
private void addObtainVia(BuilderFieldData bfd, EclipseNode node) {
|
||||
for (EclipseNode child : node.down()) {
|
||||
if (!annotationTypeMatches(ObtainVia.class, child)) continue;
|
||||
AnnotationValues<ObtainVia> ann = createAnnotation(ObtainVia.class, child);
|
||||
bfd.obtainVia = ann.getInstance();
|
||||
bfd.obtainViaNode = child;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the explicitly requested singular annotation on this node (field
|
||||
* or parameter), or null if there's no {@code @Singular} annotation on it.
|
||||
*
|
||||
* @param node The node (field or method param) to inspect for its name and potential {@code @Singular} annotation.
|
||||
*/
|
||||
private SingularData getSingularData(EclipseNode node, ASTNode source) {
|
||||
for (EclipseNode child : node.down()) {
|
||||
if (!annotationTypeMatches(Singular.class, child)) continue;
|
||||
|
||||
char[] pluralName = node.getKind() == Kind.FIELD ? removePrefixFromField(node) : ((AbstractVariableDeclaration) node.get()).name;
|
||||
AnnotationValues<Singular> ann = createAnnotation(Singular.class, child);
|
||||
String explicitSingular = ann.getInstance().value();
|
||||
if (explicitSingular.isEmpty()) {
|
||||
if (Boolean.FALSE.equals(node.getAst().readConfiguration(ConfigurationKeys.SINGULAR_AUTO))) {
|
||||
node.addError("The singular must be specified explicitly (e.g. @Singular(\"task\")) because auto singularization is disabled.");
|
||||
explicitSingular = new String(pluralName);
|
||||
} else {
|
||||
explicitSingular = autoSingularize(new String(pluralName));
|
||||
if (explicitSingular == null) {
|
||||
node.addError("Can't singularize this name; please specify the singular explicitly (i.e. @Singular(\"sheep\"))");
|
||||
explicitSingular = new String(pluralName);
|
||||
}
|
||||
}
|
||||
}
|
||||
char[] singularName = explicitSingular.toCharArray();
|
||||
|
||||
TypeReference type = ((AbstractVariableDeclaration) node.get()).type;
|
||||
TypeReference[] typeArgs = null;
|
||||
String typeName;
|
||||
if (type instanceof ParameterizedSingleTypeReference) {
|
||||
typeArgs = ((ParameterizedSingleTypeReference) type).typeArguments;
|
||||
typeName = new String(((ParameterizedSingleTypeReference) type).token);
|
||||
} else if (type instanceof ParameterizedQualifiedTypeReference) {
|
||||
TypeReference[][] tr = ((ParameterizedQualifiedTypeReference) type).typeArguments;
|
||||
if (tr != null) typeArgs = tr[tr.length - 1];
|
||||
char[][] tokens = ((ParameterizedQualifiedTypeReference) type).tokens;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
if (i > 0) sb.append(".");
|
||||
sb.append(tokens[i]);
|
||||
}
|
||||
typeName = sb.toString();
|
||||
} else {
|
||||
typeName = type.toString();
|
||||
}
|
||||
|
||||
String targetFqn = EclipseSingularsRecipes.get().toQualified(typeName);
|
||||
EclipseSingularizer singularizer = EclipseSingularsRecipes.get().getSingularizer(targetFqn);
|
||||
if (singularizer == null) {
|
||||
node.addError("Lombok does not know how to create the singular-form builder methods for type '" + typeName + "'; they won't be generated.");
|
||||
return null;
|
||||
}
|
||||
|
||||
return new SingularData(child, singularName, pluralName, typeArgs == null ? Collections.<TypeReference>emptyList() : Arrays.asList(typeArgs), targetFqn, singularizer, source);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private String generateNonclashingNameFor(String classGenericName, java.util.List<String> typeParamStrings) {
|
||||
if (!typeParamStrings.contains(classGenericName)) return classGenericName;
|
||||
int counter = 2;
|
||||
while (typeParamStrings.contains(classGenericName + counter)) counter++;
|
||||
return classGenericName + counter;
|
||||
}
|
||||
|
||||
private TypeReference[] appendBuilderTypeReferences(TypeParameter[] typeParams, String classGenericName, String builderGenericName) {
|
||||
TypeReference[] typeReferencesToAppend = new TypeReference[2];
|
||||
typeReferencesToAppend[typeReferencesToAppend.length - 2] = new SingleTypeReference(classGenericName.toCharArray(), 0);
|
||||
typeReferencesToAppend[typeReferencesToAppend.length - 1] = new SingleTypeReference(builderGenericName.toCharArray(), 0);
|
||||
return mergeToTypeReferences(typeParams, typeReferencesToAppend);
|
||||
}
|
||||
|
||||
private TypeReference[] getTypeParametersFrom(TypeReference typeRef) {
|
||||
TypeReference[][] typeArgss = null;
|
||||
if (typeRef instanceof ParameterizedQualifiedTypeReference) {
|
||||
typeArgss = ((ParameterizedQualifiedTypeReference) typeRef).typeArguments;
|
||||
} else if (typeRef instanceof ParameterizedSingleTypeReference) {
|
||||
typeArgss = new TypeReference[][] {((ParameterizedSingleTypeReference) typeRef).typeArguments};
|
||||
}
|
||||
TypeReference[] typeArgs = new TypeReference[0];
|
||||
if (typeArgss != null && typeArgss.length > 0) {
|
||||
typeArgs = typeArgss[typeArgss.length - 1];
|
||||
}
|
||||
return typeArgs;
|
||||
}
|
||||
|
||||
private static SingleTypeReference createTypeReferenceWithTypeParameters(String referenceName, TypeParameter[] typeParams) {
|
||||
if (typeParams.length > 0) {
|
||||
TypeReference[] typerefs = new TypeReference[typeParams.length];
|
||||
for (int i = 0; i < typeParams.length; i++) {
|
||||
typerefs[i] = new SingleTypeReference(typeParams[i].name, 0);
|
||||
}
|
||||
return new ParameterizedSingleTypeReference(referenceName.toCharArray(), typerefs, 0, 0);
|
||||
} else {
|
||||
return new SingleTypeReference(referenceName.toCharArray(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
private TypeReference[] mergeToTypeReferences(TypeParameter[] typeParams, TypeReference[] typeReferencesToAppend) {
|
||||
TypeReference[] typerefs = new TypeReference[typeParams.length + typeReferencesToAppend.length];
|
||||
for (int i = 0; i < typeParams.length; i++) {
|
||||
typerefs[i] = new SingleTypeReference(typeParams[i].name, 0);
|
||||
}
|
||||
for (int i = 0; i < typeReferencesToAppend.length; i++) {
|
||||
typerefs[typeParams.length + i] = typeReferencesToAppend[i];
|
||||
}
|
||||
return typerefs;
|
||||
}
|
||||
|
||||
private TypeReference[] mergeTypeReferences(TypeReference[] refs1, TypeReference[] refs2) {
|
||||
TypeReference[] result = new TypeReference[refs1.length + refs2.length];
|
||||
for (int i = 0; i < refs1.length; i++) result[i] = refs1[i];
|
||||
for (int i = 0; i < refs2.length; i++) result[refs1.length + i] = refs2[i];
|
||||
return result;
|
||||
}
|
||||
|
||||
private EclipseNode findInnerClass(EclipseNode parent, String name) {
|
||||
char[] c = name.toCharArray();
|
||||
for (EclipseNode child : parent.down()) {
|
||||
if (child.getKind() != Kind.TYPE) continue;
|
||||
TypeDeclaration td = (TypeDeclaration) child.get();
|
||||
if (Arrays.equals(td.name, c)) return child;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final char[] prefixWith(char[] prefix, char[] name) {
|
||||
char[] out = new char[prefix.length + name.length];
|
||||
System.arraycopy(prefix, 0, out, 0, prefix.length);
|
||||
System.arraycopy(name, 0, out, prefix.length, name.length);
|
||||
return out;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2017 The Project Lombok Authors.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -34,6 +34,8 @@ import lombok.core.handlers.HandlerUtil;
|
||||
import lombok.eclipse.EclipseNode;
|
||||
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 org.eclipse.jdt.internal.compiler.ast.Annotation;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Argument;
|
||||
@@ -52,13 +54,11 @@ import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
|
||||
import org.eclipse.jdt.internal.compiler.ast.OperatorIds;
|
||||
import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Statement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
|
||||
|
||||
abstract class EclipseGuavaSingularizer extends EclipseSingularizer {
|
||||
protected String getSimpleTargetTypeName(SingularData data) {
|
||||
@@ -97,18 +97,10 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer {
|
||||
return Collections.singletonList(injectFieldAndMarkGenerated(builderType, buildField));
|
||||
}
|
||||
|
||||
@Override public void generateMethods(SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, boolean chain) {
|
||||
TypeReference returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0);
|
||||
Statement returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null;
|
||||
generateSingularMethod(deprecate, returnType, returnStatement, data, builderType, fluent);
|
||||
|
||||
returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0);
|
||||
returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null;
|
||||
generatePluralMethod(deprecate, returnType, returnStatement, data, builderType, fluent);
|
||||
|
||||
returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0);
|
||||
returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null;
|
||||
generateClearMethod(deprecate, returnType, returnStatement, data, builderType);
|
||||
@Override public void generateMethods(SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, TypeReferenceMaker returnTypeMaker, StatementMaker returnStatementMaker) {
|
||||
generateSingularMethod(deprecate, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, fluent);
|
||||
generatePluralMethod(deprecate, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, fluent);
|
||||
generateClearMethod(deprecate, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType);
|
||||
}
|
||||
|
||||
void generateClearMethod(boolean deprecate, TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType) {
|
||||
@@ -200,7 +192,7 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer {
|
||||
injectMethod(builderType, md);
|
||||
}
|
||||
|
||||
@Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName) {
|
||||
@Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName, String builderVariable) {
|
||||
TypeReference varType = new QualifiedTypeReference(fromQualifiedName(data.getTargetFqn()), NULL_POSS);
|
||||
String simpleTypeName = getSimpleTargetTypeName(data);
|
||||
int agrumentsCount = getTypeArgumentsCount();
|
||||
@@ -219,14 +211,14 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer {
|
||||
invokeBuild = new MessageSend();
|
||||
invokeBuild.selector = new char[] {'b', 'u', 'i', 'l', 'd'};
|
||||
FieldReference thisDotField = new FieldReference(data.getPluralName(), 0L);
|
||||
thisDotField.receiver = new ThisReference(0, 0);
|
||||
thisDotField.receiver = getBuilderReference(builderVariable);
|
||||
invokeBuild.receiver = thisDotField;
|
||||
}
|
||||
|
||||
Expression isNull; {
|
||||
//this.pluralName == null
|
||||
FieldReference thisDotField = new FieldReference(data.getPluralName(), 0L);
|
||||
thisDotField.receiver = new ThisReference(0, 0);
|
||||
thisDotField.receiver = getBuilderReference(builderVariable);
|
||||
isNull = new EqualExpression(thisDotField, new NullLiteral(0, 0), OperatorIds.EQUAL_EQUAL);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2017 The Project Lombok Authors.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -31,6 +31,8 @@ import java.util.List;
|
||||
import lombok.core.handlers.HandlerUtil;
|
||||
import lombok.eclipse.EclipseNode;
|
||||
import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData;
|
||||
import lombok.eclipse.handlers.EclipseSingularsRecipes.StatementMaker;
|
||||
import lombok.eclipse.handlers.EclipseSingularsRecipes.TypeReferenceMaker;
|
||||
|
||||
import org.eclipse.jdt.internal.compiler.ast.Annotation;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Argument;
|
||||
@@ -45,14 +47,12 @@ 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.QualifiedTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Statement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
|
||||
|
||||
abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingularizer {
|
||||
@Override public List<char[]> listFieldsToBeGenerated(SingularData data, EclipseNode builderType) {
|
||||
@@ -88,23 +88,15 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula
|
||||
return Collections.singletonList(injectFieldAndMarkGenerated(builderType, buildField));
|
||||
}
|
||||
|
||||
@Override public void generateMethods(SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, boolean chain) {
|
||||
@Override public void generateMethods(SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, TypeReferenceMaker returnTypeMaker, StatementMaker returnStatementMaker) {
|
||||
if (useGuavaInstead(builderType)) {
|
||||
guavaListSetSingularizer.generateMethods(data, deprecate, builderType, fluent, chain);
|
||||
guavaListSetSingularizer.generateMethods(data, deprecate, builderType, fluent, returnTypeMaker, returnStatementMaker);
|
||||
return;
|
||||
}
|
||||
|
||||
TypeReference returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0);
|
||||
Statement returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null;
|
||||
generateSingularMethod(deprecate, returnType, returnStatement, data, builderType, fluent);
|
||||
|
||||
returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0);
|
||||
returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null;
|
||||
generatePluralMethod(deprecate, returnType, returnStatement, data, builderType, fluent);
|
||||
|
||||
returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0);
|
||||
returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null;
|
||||
generateClearMethod(deprecate, returnType, returnStatement, data, builderType);
|
||||
generateSingularMethod(deprecate, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, fluent);
|
||||
generatePluralMethod(deprecate, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, fluent);
|
||||
generateClearMethod(deprecate, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType);
|
||||
}
|
||||
|
||||
private void generateClearMethod(boolean deprecate, TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType) {
|
||||
|
||||
@@ -45,7 +45,6 @@ import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Statement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.SwitchStatement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
|
||||
import org.mangosdk.spi.ProviderFor;
|
||||
|
||||
@@ -56,9 +55,9 @@ public class EclipseJavaUtilListSingularizer extends EclipseJavaUtilListSetSingu
|
||||
return LombokImmutableList.of("java.util.List", "java.util.Collection", "java.lang.Iterable");
|
||||
}
|
||||
|
||||
@Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName) {
|
||||
@Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName, String builderVariable) {
|
||||
if (useGuavaInstead(builderType)) {
|
||||
guavaListSetSingularizer.appendBuildCode(data, builderType, statements, targetVariableName);
|
||||
guavaListSetSingularizer.appendBuildCode(data, builderType, statements, targetVariableName, builderVariable);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -76,7 +75,7 @@ public class EclipseJavaUtilListSingularizer extends EclipseJavaUtilListSetSingu
|
||||
/* case 1: (singleton) break; */ {
|
||||
switchContents.add(new CaseStatement(makeIntLiteral(new char[] {'1'}, null), 0, 0));
|
||||
FieldReference thisDotField = new FieldReference(data.getPluralName(), 0L);
|
||||
thisDotField.receiver = new ThisReference(0, 0);
|
||||
thisDotField.receiver = getBuilderReference(builderVariable);
|
||||
MessageSend thisDotFieldGet0 = new MessageSend();
|
||||
thisDotFieldGet0.receiver = thisDotField;
|
||||
thisDotFieldGet0.selector = new char[] {'g', 'e', 't'};
|
||||
@@ -97,7 +96,7 @@ public class EclipseJavaUtilListSingularizer extends EclipseJavaUtilListSetSingu
|
||||
Expression argToUnmodifiable;
|
||||
/* new j.u.ArrayList<Generics>(this.pluralName); */ {
|
||||
FieldReference thisDotPluralName = new FieldReference(data.getPluralName(), 0L);
|
||||
thisDotPluralName.receiver = new ThisReference(0, 0);
|
||||
thisDotPluralName.receiver = getBuilderReference(builderVariable);
|
||||
TypeReference targetTypeExpr = new QualifiedTypeReference(JAVA_UTIL_ARRAYLIST, NULL_POSS);
|
||||
targetTypeExpr = addTypeArgs(1, false, builderType, targetTypeExpr, data.getTypeArgs());
|
||||
AllocationExpression constructorCall = new AllocationExpression();
|
||||
@@ -117,7 +116,7 @@ public class EclipseJavaUtilListSingularizer extends EclipseJavaUtilListSetSingu
|
||||
|
||||
SwitchStatement switchStat = new SwitchStatement();
|
||||
switchStat.statements = switchContents.toArray(new Statement[switchContents.size()]);
|
||||
switchStat.expression = getSize(builderType, data.getPluralName(), true);
|
||||
switchStat.expression = getSize(builderType, data.getPluralName(), true, builderVariable);
|
||||
|
||||
TypeReference localShadowerType = new QualifiedTypeReference(Eclipse.fromQualifiedName(data.getTargetFqn()), NULL_POSS);
|
||||
localShadowerType = addTypeArgs(1, false, builderType, localShadowerType, data.getTypeArgs());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2017 The Project Lombok Authors.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -45,13 +45,11 @@ 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.QualifiedTypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Statement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
|
||||
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
|
||||
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
|
||||
import org.mangosdk.spi.ProviderFor;
|
||||
|
||||
import lombok.core.LombokImmutableList;
|
||||
@@ -59,6 +57,8 @@ import lombok.core.handlers.HandlerUtil;
|
||||
import lombok.eclipse.EclipseNode;
|
||||
import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer;
|
||||
import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData;
|
||||
import lombok.eclipse.handlers.EclipseSingularsRecipes.StatementMaker;
|
||||
import lombok.eclipse.handlers.EclipseSingularsRecipes.TypeReferenceMaker;
|
||||
|
||||
@ProviderFor(EclipseSingularizer.class)
|
||||
public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer {
|
||||
@@ -133,23 +133,15 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer
|
||||
return Arrays.asList(keyFieldNode, valueFieldNode);
|
||||
}
|
||||
|
||||
@Override public void generateMethods(SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, boolean chain) {
|
||||
@Override public void generateMethods(SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, TypeReferenceMaker returnTypeMaker, StatementMaker returnStatementMaker) {
|
||||
if (useGuavaInstead(builderType)) {
|
||||
guavaMapSingularizer.generateMethods(data, deprecate, builderType, fluent, chain);
|
||||
guavaMapSingularizer.generateMethods(data, deprecate, builderType, fluent, returnTypeMaker, returnStatementMaker);
|
||||
return;
|
||||
}
|
||||
|
||||
TypeReference returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0);
|
||||
Statement returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null;
|
||||
generateSingularMethod(deprecate, returnType, returnStatement, data, builderType, fluent);
|
||||
|
||||
returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0);
|
||||
returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null;
|
||||
generatePluralMethod(deprecate, returnType, returnStatement, data, builderType, fluent);
|
||||
|
||||
returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0);
|
||||
returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null;
|
||||
generateClearMethod(deprecate, returnType, returnStatement, data, builderType);
|
||||
generateSingularMethod(deprecate, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, fluent);
|
||||
generatePluralMethod(deprecate, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, fluent);
|
||||
generateClearMethod(deprecate, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType);
|
||||
}
|
||||
|
||||
private void generateClearMethod(boolean deprecate, TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType) {
|
||||
@@ -298,16 +290,16 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer
|
||||
injectMethod(builderType, md);
|
||||
}
|
||||
|
||||
@Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName) {
|
||||
@Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName, String builderVariable) {
|
||||
if (useGuavaInstead(builderType)) {
|
||||
guavaMapSingularizer.appendBuildCode(data, builderType, statements, targetVariableName);
|
||||
guavaMapSingularizer.appendBuildCode(data, builderType, statements, targetVariableName, builderVariable);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.getTargetFqn().equals("java.util.Map")) {
|
||||
statements.addAll(createJavaUtilSetMapInitialCapacitySwitchStatements(data, builderType, true, "emptyMap", "singletonMap", "LinkedHashMap"));
|
||||
statements.addAll(createJavaUtilSetMapInitialCapacitySwitchStatements(data, builderType, true, "emptyMap", "singletonMap", "LinkedHashMap", builderVariable));
|
||||
} else {
|
||||
statements.addAll(createJavaUtilSimpleCreationAndFillStatements(data, builderType, true, true, false, true, "TreeMap"));
|
||||
statements.addAll(createJavaUtilSimpleCreationAndFillStatements(data, builderType, true, true, false, true, "TreeMap", builderVariable));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,16 +37,16 @@ public class EclipseJavaUtilSetSingularizer extends EclipseJavaUtilListSetSingul
|
||||
return LombokImmutableList.of("java.util.Set", "java.util.SortedSet", "java.util.NavigableSet");
|
||||
}
|
||||
|
||||
@Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName) {
|
||||
@Override public void appendBuildCode(SingularData data, EclipseNode builderType, List<Statement> statements, char[] targetVariableName, String builderVariable) {
|
||||
if (useGuavaInstead(builderType)) {
|
||||
guavaListSetSingularizer.appendBuildCode(data, builderType, statements, targetVariableName);
|
||||
guavaListSetSingularizer.appendBuildCode(data, builderType, statements, targetVariableName, builderVariable);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.getTargetFqn().equals("java.util.Set")) {
|
||||
statements.addAll(createJavaUtilSetMapInitialCapacitySwitchStatements(data, builderType, false, "emptySet", "singleton", "LinkedHashSet"));
|
||||
statements.addAll(createJavaUtilSetMapInitialCapacitySwitchStatements(data, builderType, false, "emptySet", "singleton", "LinkedHashSet", builderVariable));
|
||||
} else {
|
||||
statements.addAll(createJavaUtilSimpleCreationAndFillStatements(data, builderType, false, true, false, true, "TreeSet"));
|
||||
statements.addAll(createJavaUtilSimpleCreationAndFillStatements(data, builderType, false, true, false, true, "TreeSet", builderVariable));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,7 +90,7 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
|
||||
return Boolean.TRUE.equals(node.getAst().readConfiguration(ConfigurationKeys.SINGULAR_USE_GUAVA));
|
||||
}
|
||||
|
||||
protected List<Statement> createJavaUtilSetMapInitialCapacitySwitchStatements(SingularData data, EclipseNode builderType, boolean mapMode, String emptyCollectionMethod, String singletonCollectionMethod, String targetType) {
|
||||
protected List<Statement> createJavaUtilSetMapInitialCapacitySwitchStatements(SingularData data, EclipseNode builderType, boolean mapMode, String emptyCollectionMethod, String singletonCollectionMethod, String targetType, String builderVariable) {
|
||||
List<Statement> switchContents = new ArrayList<Statement>();
|
||||
char[] keyName = mapMode ? (new String(data.getPluralName()) + "$key").toCharArray() : data.getPluralName();
|
||||
|
||||
@@ -112,7 +112,7 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
|
||||
/* !mapMode: pluralName = java.util.Collections.singletonCollectionMethod(this.pluralName.get(0));
|
||||
mapMode: pluralName = java.util.Collections.singletonCollectionMethod(this.pluralName$key.get(0), this.pluralName$value.get(0)); */ {
|
||||
FieldReference thisDotKey = new FieldReference(keyName, 0L);
|
||||
thisDotKey.receiver = new ThisReference(0, 0);
|
||||
thisDotKey.receiver = getBuilderReference(builderVariable);
|
||||
MessageSend thisDotKeyGet0 = new MessageSend();
|
||||
thisDotKeyGet0.receiver = thisDotKey;
|
||||
thisDotKeyGet0.selector = new char[] {'g', 'e', 't'};
|
||||
@@ -122,7 +122,7 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
|
||||
if (mapMode) {
|
||||
char[] valueName = (new String(data.getPluralName()) + "$value").toCharArray();
|
||||
FieldReference thisDotValue = new FieldReference(valueName, 0L);
|
||||
thisDotValue.receiver = new ThisReference(0, 0);
|
||||
thisDotValue.receiver = getBuilderReference(builderVariable);
|
||||
MessageSend thisDotValueGet0 = new MessageSend();
|
||||
thisDotValueGet0.receiver = thisDotValue;
|
||||
thisDotValueGet0.selector = new char[] {'g', 'e', 't'};
|
||||
@@ -143,12 +143,12 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
|
||||
|
||||
{ // default:
|
||||
switchContents.add(new CaseStatement(null, 0, 0));
|
||||
switchContents.addAll(createJavaUtilSimpleCreationAndFillStatements(data, builderType, mapMode, false, true, emptyCollectionMethod == null, targetType));
|
||||
switchContents.addAll(createJavaUtilSimpleCreationAndFillStatements(data, builderType, mapMode, false, true, emptyCollectionMethod == null, targetType, builderVariable));
|
||||
}
|
||||
|
||||
SwitchStatement switchStat = new SwitchStatement();
|
||||
switchStat.statements = switchContents.toArray(new Statement[switchContents.size()]);
|
||||
switchStat.expression = getSize(builderType, keyName, true);
|
||||
switchStat.expression = getSize(builderType, keyName, true, builderVariable);
|
||||
|
||||
TypeReference localShadowerType = new QualifiedTypeReference(fromQualifiedName(data.getTargetFqn()), NULL_POSS);
|
||||
localShadowerType = addTypeArgs(mapMode ? 2 : 1, false, builderType, localShadowerType, data.getTypeArgs());
|
||||
@@ -157,7 +157,7 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
|
||||
return Arrays.asList(varDefStat, switchStat);
|
||||
}
|
||||
|
||||
protected List<Statement> createJavaUtilSimpleCreationAndFillStatements(SingularData data, EclipseNode builderType, boolean mapMode, boolean defineVar, boolean addInitialCapacityArg, boolean nullGuard, String targetType) {
|
||||
protected List<Statement> createJavaUtilSimpleCreationAndFillStatements(SingularData data, EclipseNode builderType, boolean mapMode, boolean defineVar, boolean addInitialCapacityArg, boolean nullGuard, String targetType, String builderVariable) {
|
||||
char[] varName = mapMode ? (new String(data.getPluralName()) + "$key").toCharArray() : data.getPluralName();
|
||||
|
||||
Statement createStat; {
|
||||
@@ -166,11 +166,11 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
|
||||
if (addInitialCapacityArg) {
|
||||
// this.varName.size() < MAX_POWER_OF_2 ? 1 + this.varName.size() + (this.varName.size() - 3) / 3 : Integer.MAX_VALUE;
|
||||
// lessThanCutOff = this.varName.size() < MAX_POWER_OF_2
|
||||
Expression lessThanCutoff = new BinaryExpression(getSize(builderType, varName, nullGuard), makeIntLiteral("0x40000000".toCharArray(), null), OperatorIds.LESS);
|
||||
Expression lessThanCutoff = new BinaryExpression(getSize(builderType, varName, nullGuard, builderVariable), makeIntLiteral("0x40000000".toCharArray(), null), OperatorIds.LESS);
|
||||
FieldReference integerMaxValue = new FieldReference("MAX_VALUE".toCharArray(), 0L);
|
||||
integerMaxValue.receiver = new QualifiedNameReference(TypeConstants.JAVA_LANG_INTEGER, NULL_POSS, 0, 0);
|
||||
Expression sizeFormulaLeft = new BinaryExpression(makeIntLiteral(new char[] {'1'}, null), getSize(builderType, varName, nullGuard), OperatorIds.PLUS);
|
||||
Expression sizeFormulaRightLeft = new BinaryExpression(getSize(builderType, varName, nullGuard), makeIntLiteral(new char[] {'3'}, null), OperatorIds.MINUS);
|
||||
Expression sizeFormulaLeft = new BinaryExpression(makeIntLiteral(new char[] {'1'}, null), getSize(builderType, varName, nullGuard, builderVariable), OperatorIds.PLUS);
|
||||
Expression sizeFormulaRightLeft = new BinaryExpression(getSize(builderType, varName, nullGuard, builderVariable), makeIntLiteral(new char[] {'3'}, null), OperatorIds.MINUS);
|
||||
Expression sizeFormulaRight = new BinaryExpression(sizeFormulaRightLeft, makeIntLiteral(new char[] {'3'}, null), OperatorIds.DIVIDE);
|
||||
Expression sizeFormula = new BinaryExpression(sizeFormulaLeft, sizeFormulaRight, OperatorIds.PLUS);
|
||||
Expression cond = new ConditionalExpression(lessThanCutoff, sizeFormula, integerMaxValue);
|
||||
@@ -203,9 +203,9 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
|
||||
pluralnameDotPut.selector = new char[] {'p', 'u', 't'};
|
||||
pluralnameDotPut.receiver = new SingleNameReference(data.getPluralName(), 0L);
|
||||
FieldReference thisDotKey = new FieldReference(varName, 0L);
|
||||
thisDotKey.receiver = new ThisReference(0, 0);
|
||||
thisDotKey.receiver = getBuilderReference(builderVariable);
|
||||
FieldReference thisDotValue = new FieldReference((new String(data.getPluralName()) + "$value").toCharArray(), 0L);
|
||||
thisDotValue.receiver = new ThisReference(0, 0);
|
||||
thisDotValue.receiver = getBuilderReference(builderVariable);
|
||||
MessageSend keyArg = new MessageSend();
|
||||
keyArg.receiver = thisDotKey;
|
||||
keyArg.arguments = new Expression[] {new SingleNameReference(iVar, 0L)};
|
||||
@@ -219,7 +219,7 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
|
||||
LocalDeclaration forInit = new LocalDeclaration(iVar, 0, 0);
|
||||
forInit.type = TypeReference.baseTypeReference(TypeIds.T_int, 0);
|
||||
forInit.initialization = makeIntLiteral(new char[] {'0'}, null);
|
||||
Expression checkExpr = new BinaryExpression(new SingleNameReference(iVar, 0L), getSize(builderType, varName, nullGuard), OperatorIds.LESS);
|
||||
Expression checkExpr = new BinaryExpression(new SingleNameReference(iVar, 0L), getSize(builderType, varName, nullGuard, builderVariable), OperatorIds.LESS);
|
||||
Expression incrementExpr = new PostfixExpression(new SingleNameReference(iVar, 0L), IntLiteral.One, OperatorIds.PLUS, 0);
|
||||
fillStat = new ForStatement(new Statement[] {forInit}, checkExpr, new Statement[] {incrementExpr}, pluralnameDotPut, true, 0, 0);
|
||||
} else {
|
||||
@@ -228,14 +228,14 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer {
|
||||
pluralnameDotAddAll.selector = new char[] {'a', 'd', 'd', 'A', 'l', 'l'};
|
||||
pluralnameDotAddAll.receiver = new SingleNameReference(data.getPluralName(), 0L);
|
||||
FieldReference thisDotPluralname = new FieldReference(varName, 0L);
|
||||
thisDotPluralname.receiver = new ThisReference(0, 0);
|
||||
thisDotPluralname.receiver = getBuilderReference(builderVariable);
|
||||
pluralnameDotAddAll.arguments = new Expression[] {thisDotPluralname};
|
||||
fillStat = pluralnameDotAddAll;
|
||||
}
|
||||
|
||||
if (nullGuard) {
|
||||
FieldReference thisDotField = new FieldReference(varName, 0L);
|
||||
thisDotField.receiver = new ThisReference(0, 0);
|
||||
thisDotField.receiver = getBuilderReference(builderVariable);
|
||||
Expression cond = new EqualExpression(thisDotField, new NullLiteral(0, 0), OperatorIds.NOT_EQUAL);
|
||||
fillStat = new IfStatement(cond, fillStat, 0, 0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package lombok.experimental;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import lombok.Singular;
|
||||
|
||||
/**
|
||||
* The SuperBuilder annotation creates a so-called 'builder' aspect to the class that is annotated with {@code @SuperBuilder}, but which works well when extending.
|
||||
* It is similar to {@code @Builder}, except it is only legal on types, is less configurable, but allows you to {@code extends} other builder-able classes.
|
||||
* <p>
|
||||
* All classes in the hierarchy must be annotated with {@code @SuperBuilder}.
|
||||
* <p>
|
||||
* Lombok generates 2 inner 'builder' classes, which extend the parent class' builder class (unless your class doesn't have an extends clause).
|
||||
* Lombok also generates a static method named {@code builder()}, and a protected constructor that takes 1 argument of the builderclass type.
|
||||
* <p>
|
||||
* The <code><strong>T</strong>Builder</code> class contains 1 method for each parameter of the annotated
|
||||
* constructor / method (each field, when annotating a class), which returns the builder itself.
|
||||
* 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)
|
||||
@Retention(SOURCE)
|
||||
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.
|
||||
*
|
||||
* @return Whether to generate a {@code toBuilder()} method.
|
||||
*/
|
||||
// boolean toBuilder() default false;
|
||||
}
|
||||
@@ -550,7 +550,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
|
||||
bfd.singularData.getSingularizer().appendBuildCode(bfd.singularData, type, source, statements, bfd.name);
|
||||
bfd.singularData.getSingularizer().appendBuildCode(bfd.singularData, type, source, statements, bfd.name, "this");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import lombok.Builder;
|
||||
import lombok.core.AST.Kind;
|
||||
import lombok.core.AnnotationValues;
|
||||
import lombok.core.HandlerPriority;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import lombok.javac.JavacAnnotationHandler;
|
||||
import lombok.javac.JavacNode;
|
||||
|
||||
@@ -41,8 +42,9 @@ public class HandleBuilderDefault extends JavacAnnotationHandler<Builder.Default
|
||||
JavacNode annotatedField = annotationNode.up();
|
||||
if (annotatedField.getKind() != Kind.FIELD) return;
|
||||
JavacNode classWithAnnotatedField = annotatedField.up();
|
||||
if (!hasAnnotation(Builder.class, classWithAnnotatedField) && !hasAnnotation("lombok.experimental.Builder", classWithAnnotatedField)) {
|
||||
annotationNode.addWarning("@Builder.Default requires @Builder on the class for it to mean anything.");
|
||||
if (!hasAnnotation(Builder.class, classWithAnnotatedField) && !hasAnnotation("lombok.experimental.Builder", classWithAnnotatedField)
|
||||
&& !hasAnnotation(SuperBuilder.class, classWithAnnotatedField)) {
|
||||
annotationNode.addWarning("@Builder.Default requires @Builder or @SuperBuilder on the class for it to mean anything.");
|
||||
deleteAnnotationIfNeccessary(annotationNode, Builder.Default.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,6 +207,17 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> {
|
||||
}
|
||||
|
||||
public static JCMethodDecl createSetter(long access, boolean deprecate, JavacNode field, JavacTreeMaker treeMaker, String setterName, Name booleanFieldToSet, boolean shouldReturnThis, JavacNode source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) {
|
||||
JCExpression returnType = null;
|
||||
JCReturn returnStatement = null;
|
||||
if (shouldReturnThis) {
|
||||
returnType = cloneSelfType(field);
|
||||
returnStatement = treeMaker.Return(treeMaker.Ident(field.toName("this")));
|
||||
}
|
||||
|
||||
return createSetter(access, deprecate, field, treeMaker, setterName, booleanFieldToSet, returnType, returnStatement, source, onMethod, onParam);
|
||||
}
|
||||
|
||||
public static JCMethodDecl createSetter(long access, boolean deprecate, JavacNode field, JavacTreeMaker treeMaker, String setterName, Name booleanFieldToSet, JCExpression methodType, JCStatement returnStatement, JavacNode source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) {
|
||||
if (setterName == null) return null;
|
||||
|
||||
JCVariableDecl fieldDecl = (JCVariableDecl) field.get();
|
||||
@@ -237,21 +248,13 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> {
|
||||
statements.append(treeMaker.Exec(setBool));
|
||||
}
|
||||
|
||||
JCExpression methodType = null;
|
||||
if (shouldReturnThis) {
|
||||
methodType = cloneSelfType(field);
|
||||
}
|
||||
|
||||
if (methodType == null) {
|
||||
//WARNING: Do not use field.getSymbolTable().voidType - that field has gone through non-backwards compatible API changes within javac1.6.
|
||||
methodType = treeMaker.Type(Javac.createVoidType(field.getSymbolTable(), CTC_VOID));
|
||||
shouldReturnThis = false;
|
||||
returnStatement = null;
|
||||
}
|
||||
|
||||
if (shouldReturnThis) {
|
||||
JCReturn returnStatement = treeMaker.Return(treeMaker.Ident(field.toName("this")));
|
||||
statements.append(returnStatement);
|
||||
}
|
||||
if (returnStatement != null) statements.append(returnStatement);
|
||||
|
||||
JCBlock methodBody = treeMaker.Block(0, statements.toList());
|
||||
List<JCTypeParameter> methodGenericParams = List.nil();
|
||||
|
||||
@@ -0,0 +1,738 @@
|
||||
/*
|
||||
* Copyright (C) 2013-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
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package lombok.javac.handlers;
|
||||
|
||||
import static lombok.core.handlers.HandlerUtil.*;
|
||||
import static lombok.javac.Javac.*;
|
||||
import static lombok.javac.handlers.JavacHandlerUtil.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.mangosdk.spi.ProviderFor;
|
||||
|
||||
import com.sun.tools.javac.code.BoundKind;
|
||||
import com.sun.tools.javac.code.Flags;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
|
||||
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.JCFieldAccess;
|
||||
import com.sun.tools.javac.tree.JCTree.JCIdent;
|
||||
import com.sun.tools.javac.tree.JCTree.JCIf;
|
||||
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.JCStatement;
|
||||
import com.sun.tools.javac.tree.JCTree.JCTypeApply;
|
||||
import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
|
||||
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCWildcard;
|
||||
import com.sun.tools.javac.util.List;
|
||||
import com.sun.tools.javac.util.ListBuffer;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Builder;
|
||||
import lombok.Builder.ObtainVia;
|
||||
import lombok.ConfigurationKeys;
|
||||
import lombok.Singular;
|
||||
import lombok.ToString;
|
||||
import lombok.core.AST.Kind;
|
||||
import lombok.core.AnnotationValues;
|
||||
import lombok.core.HandlerPriority;
|
||||
import lombok.core.handlers.HandlerUtil;
|
||||
import lombok.core.handlers.InclusionExclusionUtils.Included;
|
||||
import lombok.experimental.NonFinal;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import lombok.javac.Javac;
|
||||
import lombok.javac.JavacAnnotationHandler;
|
||||
import lombok.javac.JavacNode;
|
||||
import lombok.javac.JavacTreeMaker;
|
||||
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;
|
||||
|
||||
@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 {
|
||||
JCExpression type;
|
||||
Name rawName;
|
||||
Name name;
|
||||
Name nameOfSetFlag;
|
||||
SingularData singularData;
|
||||
ObtainVia obtainVia;
|
||||
JavacNode obtainViaNode;
|
||||
JavacNode originalFieldNode;
|
||||
|
||||
java.util.List<JavacNode> createdFields = new ArrayList<JavacNode>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(AnnotationValues<SuperBuilder> annotation, JCAnnotation ast, JavacNode annotationNode) {
|
||||
handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.SUPERBUILDER_FLAG_USAGE, "@SuperBuilder");
|
||||
|
||||
SuperBuilder superbuilderAnnotation = annotation.getInstance();
|
||||
deleteAnnotationIfNeccessary(annotationNode, SuperBuilder.class);
|
||||
|
||||
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;
|
||||
|
||||
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();
|
||||
|
||||
boolean addCleaning = false;
|
||||
|
||||
if (!(tdParent.get() instanceof JCClassDecl)) {
|
||||
annotationNode.addError("@SuperBuilder is only supported on types.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Gather all fields of the class that should be set by the builder.
|
||||
JCClassDecl td = (JCClassDecl) tdParent.get();
|
||||
ListBuffer<JavacNode> allFields = new ListBuffer<JavacNode>();
|
||||
boolean valuePresent = (hasAnnotation(lombok.Value.class, tdParent) || hasAnnotation("lombok.experimental.Value", tdParent));
|
||||
for (JavacNode fieldNode : HandleConstructor.findAllFields(tdParent, true)) {
|
||||
JCVariableDecl fd = (JCVariableDecl) fieldNode.get();
|
||||
JavacNode isDefault = findAnnotation(Builder.Default.class, fieldNode, true);
|
||||
boolean isFinal = (fd.mods.flags & Flags.FINAL) != 0 || (valuePresent && !hasAnnotation(NonFinal.class, fieldNode));
|
||||
BuilderFieldData bfd = new BuilderFieldData();
|
||||
bfd.rawName = fd.name;
|
||||
bfd.name = removePrefixFromField(fieldNode);
|
||||
bfd.type = fd.vartype;
|
||||
bfd.singularData = getSingularData(fieldNode);
|
||||
bfd.originalFieldNode = fieldNode;
|
||||
|
||||
if (bfd.singularData != null && isDefault != null) {
|
||||
isDefault.addError("@Builder.Default and @Singular cannot be mixed.");
|
||||
isDefault = null;
|
||||
}
|
||||
|
||||
if (fd.init == null && isDefault != null) {
|
||||
isDefault.addWarning("@Builder.Default requires an initializing expression (' = something;').");
|
||||
isDefault = null;
|
||||
}
|
||||
|
||||
if (fd.init != null && isDefault == null) {
|
||||
if (isFinal) continue;
|
||||
fieldNode.addWarning("@SuperBuilder will ignore the initializing expression entirely. If you want the initializing expression to serve as default, add @Builder.Default. If it is not supposed to be settable during building, make the field final.");
|
||||
}
|
||||
|
||||
if (isDefault != null) {
|
||||
bfd.nameOfSetFlag = tdParent.toName(bfd.name + "$set");
|
||||
// The @Builder annotation removes the initializing expression on the field and moves
|
||||
// it to a method called "$default$FIELDNAME". This method is then called upon building.
|
||||
// We do NOT do this, because this is unexpected and may lead to bugs when using other
|
||||
// constructors (see, e.g., issue #1347).
|
||||
// Instead, we keep the init expression and only set a new value in the builder-based
|
||||
// constructor if it was set in the builder. Drawback is that the init expression is
|
||||
// always executed, even if it was unnecessary because its value is overwritten by the
|
||||
// builder.
|
||||
// TODO: Once the issue is resolved in @Builder, we can adapt the solution here.
|
||||
}
|
||||
addObtainVia(bfd, fieldNode);
|
||||
builderFields.add(bfd);
|
||||
allFields.append(fieldNode);
|
||||
}
|
||||
|
||||
// Set the names of the builder classes.
|
||||
String builderClassName = td.name.toString() + "Builder";
|
||||
String builderImplClassName = builderClassName + "Impl";
|
||||
JCTree extendsClause = Javac.getExtendsClause(td);
|
||||
JCExpression superclassBuilderClassExpression = null;
|
||||
if (extendsClause instanceof JCTypeApply) {
|
||||
// Remember the type arguments, because we need them for the extends clause of our abstract builder class.
|
||||
superclassTypeParams = ((JCTypeApply) extendsClause).getTypeArguments();
|
||||
// A class name with a generics type, e.g., "Superclass<A>".
|
||||
extendsClause = ((JCTypeApply) extendsClause).getType();
|
||||
}
|
||||
if (extendsClause instanceof JCFieldAccess) {
|
||||
Name superclassClassName = ((JCFieldAccess)extendsClause).getIdentifier();
|
||||
String superclassBuilderClassName = superclassClassName + "Builder";
|
||||
superclassBuilderClassExpression = tdParent.getTreeMaker().Select((JCFieldAccess) extendsClause,
|
||||
tdParent.toName(superclassBuilderClassName));
|
||||
} else if (extendsClause != null) {
|
||||
String superclassBuilderClassName = extendsClause.toString() + "Builder";
|
||||
superclassBuilderClassExpression = chainDots(tdParent, extendsClause.toString(), superclassBuilderClassName);
|
||||
}
|
||||
// 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.
|
||||
String classGenericName = "C";
|
||||
String builderGenericName = "B";
|
||||
// If these generics' names collide with any generics on the annotated class, modify them.
|
||||
// For instance, if there are generics <B, B2, C> on the annotated class, use "C2" and "B3" for our builder.
|
||||
java.util.List<String> typeParamStrings = new ArrayList<String>();
|
||||
for (JCTypeParameter typeParam : typeParams) typeParamStrings.add(typeParam.getName().toString());
|
||||
classGenericName = generateNonclashingNameFor(classGenericName, typeParamStrings);
|
||||
builderGenericName = generateNonclashingNameFor(builderGenericName, typeParamStrings);
|
||||
|
||||
thrownExceptions = List.nil();
|
||||
|
||||
// Check validity of @ObtainVia fields, and add check if adding cleaning for @Singular is necessary.
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
|
||||
if (bfd.singularData.getSingularizer().requiresCleaning()) {
|
||||
addCleaning = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bfd.obtainVia != null) {
|
||||
if (bfd.obtainVia.field().isEmpty() == bfd.obtainVia.method().isEmpty()) {
|
||||
bfd.obtainViaNode.addError("The syntax is either @ObtainVia(field = \"fieldName\") or @ObtainVia(method = \"methodName\").");
|
||||
return;
|
||||
}
|
||||
if (bfd.obtainVia.method().isEmpty() && bfd.obtainVia.isStatic()) {
|
||||
bfd.obtainViaNode.addError("@ObtainVia(isStatic = true) is not valid unless 'method' has been set.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the abstract builder class.
|
||||
JavacNode builderType = findInnerClass(tdParent, builderClassName);
|
||||
if (builderType == null) {
|
||||
builderType = generateBuilderAbstractClass(annotationNode, tdParent, builderClassName, superclassBuilderClassExpression,
|
||||
typeParams, superclassTypeParams, ast, classGenericName, builderGenericName);
|
||||
} else {
|
||||
annotationNode.addError("@SuperBuilder does not support customized builders. Use @Builder instead.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate the fields in the abstract builder class that hold the values for the instance.
|
||||
generateBuilderFields(builderType, builderFields, ast);
|
||||
if (addCleaning) {
|
||||
JavacTreeMaker maker = builderType.getTreeMaker();
|
||||
JCVariableDecl uncleanField = maker.VarDef(maker.Modifiers(Flags.PRIVATE), builderType.toName("$lombokUnclean"), maker.TypeIdent(CTC_BOOLEAN), null);
|
||||
injectFieldAndMarkGenerated(builderType, uncleanField);
|
||||
}
|
||||
|
||||
// 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));
|
||||
|
||||
// Create the setter methods in the abstract builder.
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
generateSetterMethodsForBuilder(builderType, bfd, annotationNode, builderGenericName);
|
||||
}
|
||||
|
||||
// Create the toString() method for the abstract builder.
|
||||
java.util.List<Included<JavacNode, ToString.Include>> fieldNodes = new ArrayList<Included<JavacNode, ToString.Include>>();
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
for (JavacNode f : bfd.createdFields) {
|
||||
fieldNodes.add(new Included<JavacNode, ToString.Include>(f, null, true));
|
||||
}
|
||||
}
|
||||
|
||||
// Let toString() call super.toString() if there is a superclass, so that it also shows fields from the superclass' builder.
|
||||
JCMethodDecl toStringMethod = HandleToString.createToString(builderType, fieldNodes, true, superclassBuilderClassExpression != null, FieldAccess.ALWAYS_FIELD, ast);
|
||||
if (toStringMethod != null) injectMethod(builderType, toStringMethod);
|
||||
|
||||
// If clean methods are requested, add them now.
|
||||
if (addCleaning) injectMethod(builderType, generateCleanMethod(builderFields, builderType, ast));
|
||||
|
||||
recursiveSetGeneratedBy(builderType.get(), ast, annotationNode.getContext());
|
||||
|
||||
if ((td.mods.flags & Flags.ABSTRACT) == 0) {
|
||||
// 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);
|
||||
} 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));
|
||||
injectMethod(builderImplType, generateBuildMethod(buildMethodName, returnType, builderImplType, thrownExceptions));
|
||||
|
||||
recursiveSetGeneratedBy(builderImplType.get(), ast, annotationNode.getContext());
|
||||
}
|
||||
|
||||
// Generate a constructor in the annotated class that takes a builder as argument.
|
||||
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.
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns the abstract builder class and injects it into the annotated class.
|
||||
*/
|
||||
private JavacNode generateBuilderAbstractClass(JavacNode source, JavacNode tdParent, String builderClass,
|
||||
JCExpression superclassBuilderClassExpression, List<JCTypeParameter> typeParams,
|
||||
List<JCExpression> superclassTypeParams, JCAnnotation ast, String classGenericName, String builderGenericName) {
|
||||
|
||||
JavacTreeMaker maker = tdParent.getTreeMaker();
|
||||
JCModifiers mods = maker.Modifiers(Flags.STATIC | Flags.ABSTRACT | Flags.PUBLIC);
|
||||
|
||||
// Keep any type params of the annotated class.
|
||||
ListBuffer<JCTypeParameter> allTypeParams = new ListBuffer<JCTypeParameter>();
|
||||
allTypeParams.addAll(copyTypeParams(source, typeParams));
|
||||
// Add builder-specific type params required for inheritable builders.
|
||||
// 1. The return type for the build() method, named "C", which extends the annotated class.
|
||||
JCExpression annotatedClass = maker.Ident(tdParent.toName(tdParent.getName()));
|
||||
if (typeParams.nonEmpty()) {
|
||||
// Add type params of the annotated class.
|
||||
annotatedClass = maker.TypeApply(annotatedClass, getTypeParamExpressions(typeParams, maker).toList());
|
||||
}
|
||||
allTypeParams.add(maker.TypeParameter(tdParent.toName(classGenericName), List.<JCExpression>of(annotatedClass)));
|
||||
// 2. The return type for all setter methods, named "B", which extends this builder class.
|
||||
Name builderClassName = tdParent.toName(builderClass);
|
||||
ListBuffer<JCExpression> typeParamsForBuilder = getTypeParamExpressions(typeParams, maker);
|
||||
typeParamsForBuilder.add(maker.Ident(tdParent.toName(classGenericName)));
|
||||
typeParamsForBuilder.add(maker.Ident(tdParent.toName(builderGenericName)));
|
||||
JCTypeApply typeApply = maker.TypeApply(maker.Ident(builderClassName), typeParamsForBuilder.toList());
|
||||
allTypeParams.add(maker.TypeParameter(tdParent.toName(builderGenericName), List.<JCExpression>of(typeApply)));
|
||||
|
||||
JCExpression extending = null;
|
||||
if (superclassBuilderClassExpression != null) {
|
||||
// If the annotated class extends another class, we want this builder to extend the builder of the superclass.
|
||||
// 1. Add the type parameters of the superclass.
|
||||
typeParamsForBuilder = getTypeParamExpressions(superclassTypeParams, maker);
|
||||
// 2. Add the builder type params <C, B>.
|
||||
typeParamsForBuilder.add(maker.Ident(tdParent.toName(classGenericName)));
|
||||
typeParamsForBuilder.add(maker.Ident(tdParent.toName(builderGenericName)));
|
||||
extending = maker.TypeApply(superclassBuilderClassExpression, typeParamsForBuilder.toList());
|
||||
}
|
||||
|
||||
JCClassDecl builder = maker.ClassDef(mods, builderClassName, allTypeParams.toList(), extending, List.<JCExpression>nil(), List.<JCTree>nil());
|
||||
return injectType(tdParent, builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
JavacTreeMaker maker = tdParent.getTreeMaker();
|
||||
JCModifiers mods = maker.Modifiers(Flags.STATIC | Flags.PRIVATE | Flags.FINAL);
|
||||
|
||||
// Extend the abstract builder.
|
||||
JCExpression extending = maker.Ident(tdParent.toName(builderAbstractClass));
|
||||
// Add any type params of the annotated class.
|
||||
ListBuffer<JCTypeParameter> allTypeParams = new ListBuffer<JCTypeParameter>();
|
||||
allTypeParams.addAll(copyTypeParams(source, typeParams));
|
||||
// Add builder-specific type params required for inheritable builders.
|
||||
// 1. The return type for the build() method (named "C" in the abstract builder), which is the annotated class.
|
||||
JCExpression annotatedClass = maker.Ident(tdParent.toName(tdParent.getName()));
|
||||
if (typeParams.nonEmpty()) {
|
||||
// Add type params of the annotated class.
|
||||
annotatedClass = maker.TypeApply(annotatedClass, getTypeParamExpressions(typeParams, maker).toList());
|
||||
}
|
||||
// 2. The return type for all setter methods (named "B" in the abstract builder), which is this builder class.
|
||||
JCExpression builderImplClassExpression = maker.Ident(tdParent.toName(builderImplClass));
|
||||
if (typeParams.nonEmpty()) {
|
||||
builderImplClassExpression = maker.TypeApply(builderImplClassExpression, getTypeParamExpressions(typeParams, maker).toList());
|
||||
}
|
||||
ListBuffer<JCExpression> typeParamsForBuilder = getTypeParamExpressions(typeParams, maker);
|
||||
typeParamsForBuilder.add(annotatedClass);
|
||||
typeParamsForBuilder.add(builderImplClassExpression);
|
||||
extending = maker.TypeApply(extending, typeParamsForBuilder.toList());
|
||||
|
||||
JCClassDecl builder = maker.ClassDef(mods, tdParent.toName(builderImplClass), copyTypeParams(source, typeParams), extending, List.<JCExpression>nil(), List.<JCTree>nil());
|
||||
return injectType(tdParent, builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a constructor that has a builder as the only parameter.
|
||||
* The values from the builder are used to initialize the fields of new instances.
|
||||
*
|
||||
* @param typeNode
|
||||
* the type (with the {@code @Builder} annotation) for which a
|
||||
* constructor should be generated.
|
||||
* @param typeParams
|
||||
* @param builderFields a list of fields in the builder which should be assigned to new instances.
|
||||
* @param source the annotation (used for setting source code locations for the generated code).
|
||||
* @param callBuilderBasedSuperConstructor
|
||||
* If {@code true}, the constructor will explicitly call a super
|
||||
* constructor with the builder as argument. Requires
|
||||
* {@code builderClassAsParameter != null}.
|
||||
*/
|
||||
private void generateBuilderBasedConstructor(JavacNode typeNode, List<JCTypeParameter> typeParams, java.util.List<BuilderFieldData> builderFields, JavacNode source, String builderClassName, boolean callBuilderBasedSuperConstructor) {
|
||||
JavacTreeMaker maker = typeNode.getTreeMaker();
|
||||
|
||||
AccessLevel level = AccessLevel.PROTECTED;
|
||||
|
||||
ListBuffer<JCStatement> nullChecks = new ListBuffer<JCStatement>();
|
||||
ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();
|
||||
|
||||
Name builderVariableName = typeNode.toName("b");
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
List<JCAnnotation> nonNulls = findAnnotations(bfd.originalFieldNode, NON_NULL_PATTERN);
|
||||
if (!nonNulls.isEmpty()) {
|
||||
JCStatement nullCheck = generateNullCheck(maker, bfd.originalFieldNode, source);
|
||||
if (nullCheck != null) nullChecks.append(nullCheck);
|
||||
}
|
||||
|
||||
JCExpression rhs;
|
||||
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
|
||||
bfd.singularData.getSingularizer().appendBuildCode(bfd.singularData, bfd.originalFieldNode, bfd.type, statements, bfd.name, "b");
|
||||
rhs = maker.Ident(bfd.singularData.getPluralName());
|
||||
} else {
|
||||
rhs = maker.Select(maker.Ident(builderVariableName), bfd.rawName);
|
||||
}
|
||||
JCFieldAccess thisX = maker.Select(maker.Ident(typeNode.toName("this")), bfd.rawName);
|
||||
|
||||
JCStatement assign = maker.Exec(maker.Assign(thisX, rhs));
|
||||
|
||||
// In case of @Builder.Default, only set the value if it really was set in the builder.
|
||||
if (bfd.nameOfSetFlag != null) {
|
||||
JCFieldAccess setField = maker.Select(maker.Ident(builderVariableName), bfd.nameOfSetFlag);
|
||||
JCIf ifSet = maker.If(setField, assign, null);
|
||||
statements.append(ifSet);
|
||||
} else {
|
||||
statements.append(assign);
|
||||
}
|
||||
}
|
||||
|
||||
JCModifiers mods = maker.Modifiers(toJavacModifier(level), List.<JCAnnotation>nil());
|
||||
|
||||
// Create a constructor that has just the builder as parameter.
|
||||
ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
|
||||
long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, typeNode.getContext());
|
||||
Name builderClassname = typeNode.toName(builderClassName);
|
||||
// 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 paramType = maker.TypeApply(maker.Ident(builderClassname), typeParamsForBuilderParameter.toList());
|
||||
JCVariableDecl param = maker.VarDef(maker.Modifiers(flags), builderVariableName, paramType, null);
|
||||
params.append(param);
|
||||
|
||||
if (callBuilderBasedSuperConstructor) {
|
||||
// The first statement must be the call to the super constructor.
|
||||
JCMethodInvocation callToSuperConstructor = maker.Apply(List.<JCExpression>nil(),
|
||||
maker.Ident(typeNode.toName("super")),
|
||||
List.<JCExpression>of(maker.Ident(builderVariableName)));
|
||||
statements.prepend(maker.Exec(callToSuperConstructor));
|
||||
}
|
||||
|
||||
JCMethodDecl constr = recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("<init>"),
|
||||
null, List.<JCTypeParameter>nil(), params.toList(), List.<JCExpression>nil(),
|
||||
maker.Block(0L, nullChecks.appendList(statements).toList()), null), source.get(), typeNode.getContext());
|
||||
|
||||
injectMethod(typeNode, constr, null, Javac.createVoidType(typeNode.getSymbolTable(), CTC_VOID));
|
||||
}
|
||||
|
||||
private JCMethodDecl generateBuilderMethod(String builderMethodName, 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 call = maker.NewClass(null, List.<JCExpression>nil(), namePlusTypeParamsToTypeReference(maker, type.toName(builderImplClassName), typeParams), List.<JCExpression>nil(), null);
|
||||
JCStatement statement = maker.Return(call);
|
||||
|
||||
JCBlock body = maker.Block(0, List.<JCStatement>of(statement));
|
||||
int modifiers = Flags.PUBLIC;
|
||||
modifiers |= Flags.STATIC;
|
||||
|
||||
// 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(builderMethodName), returnType, copyTypeParams(source, typeParams), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null);
|
||||
}
|
||||
|
||||
private JCMethodDecl generateAbstractSelfMethod(JavacNode type, boolean override, String builderGenericName) {
|
||||
JavacTreeMaker maker = type.getTreeMaker();
|
||||
List<JCAnnotation> annotations = List.nil();
|
||||
if (override) {
|
||||
JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(type, "Override"), List.<JCExpression>nil());
|
||||
annotations = List.of(overrideAnnotation);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
private JCMethodDecl generateSelfMethod(JavacNode builderImplType) {
|
||||
JavacTreeMaker maker = builderImplType.getTreeMaker();
|
||||
|
||||
JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(builderImplType, "Override"), List.<JCExpression>nil());
|
||||
JCModifiers modifiers = maker.Modifiers(Flags.PROTECTED, List.of(overrideAnnotation));
|
||||
Name name = builderImplType.toName(SELF_METHOD);
|
||||
JCExpression returnType = maker.Ident(builderImplType.toName(builderImplType.getName()));
|
||||
|
||||
JCStatement statement = maker.Return(maker.Ident(builderImplType.toName("this")));
|
||||
JCBlock body = maker.Block(0, List.<JCStatement>of(statement));
|
||||
|
||||
return maker.MethodDef(modifiers, name, returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null);
|
||||
}
|
||||
|
||||
private JCMethodDecl generateAbstractBuildMethod(JavacNode type, String methodName, boolean override, String classGenericName) {
|
||||
JavacTreeMaker maker = type.getTreeMaker();
|
||||
List<JCAnnotation> annotations = List.nil();
|
||||
if (override) {
|
||||
JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(type, "Override"), List.<JCExpression>nil());
|
||||
annotations = List.of(overrideAnnotation);
|
||||
}
|
||||
JCModifiers modifiers = maker.Modifiers(Flags.PUBLIC | Flags.ABSTRACT, annotations);
|
||||
Name name = type.toName(methodName);
|
||||
JCExpression returnType = maker.Ident(type.toName(classGenericName));
|
||||
|
||||
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) {
|
||||
JavacTreeMaker maker = type.getTreeMaker();
|
||||
|
||||
JCExpression call;
|
||||
ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();
|
||||
|
||||
// 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);
|
||||
statements.append(maker.Return(call));
|
||||
|
||||
JCBlock body = maker.Block(0, statements.toList());
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private JCMethodDecl generateCleanMethod(java.util.List<BuilderFieldData> builderFields, JavacNode type, JCTree source) {
|
||||
JavacTreeMaker maker = type.getTreeMaker();
|
||||
ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();
|
||||
|
||||
for (BuilderFieldData bfd : builderFields) {
|
||||
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
|
||||
bfd.singularData.getSingularizer().appendCleaningCode(bfd.singularData, type, source, statements);
|
||||
}
|
||||
}
|
||||
|
||||
statements.append(maker.Exec(maker.Assign(maker.Select(maker.Ident(type.toName("this")), type.toName("$lombokUnclean")), maker.Literal(CTC_BOOLEAN, 0))));
|
||||
JCBlock body = maker.Block(0, statements.toList());
|
||||
return maker.MethodDef(maker.Modifiers(Flags.PUBLIC), type.toName("$lombokClean"), maker.Type(Javac.createVoidType(type.getSymbolTable(), CTC_VOID)), List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null);
|
||||
}
|
||||
|
||||
private void generateBuilderFields(JavacNode builderType, java.util.List<BuilderFieldData> builderFields, JCTree source) {
|
||||
int len = builderFields.size();
|
||||
java.util.List<JavacNode> existing = new ArrayList<JavacNode>();
|
||||
for (JavacNode child : builderType.down()) {
|
||||
if (child.getKind() == Kind.FIELD) existing.add(child);
|
||||
}
|
||||
|
||||
for (int i = len - 1; i >= 0; i--) {
|
||||
BuilderFieldData bfd = builderFields.get(i);
|
||||
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
|
||||
bfd.createdFields.addAll(bfd.singularData.getSingularizer().generateFields(bfd.singularData, builderType, source));
|
||||
} else {
|
||||
JavacNode field = null, setFlag = null;
|
||||
for (JavacNode exists : existing) {
|
||||
Name n = ((JCVariableDecl) exists.get()).name;
|
||||
if (n.equals(bfd.name)) field = exists;
|
||||
if (n.equals(bfd.nameOfSetFlag)) setFlag = exists;
|
||||
}
|
||||
JavacTreeMaker maker = builderType.getTreeMaker();
|
||||
if (field == null) {
|
||||
JCModifiers mods = maker.Modifiers(Flags.PRIVATE);
|
||||
JCVariableDecl newField = maker.VarDef(mods, bfd.name, cloneType(maker, bfd.type, source, builderType.getContext()), null);
|
||||
field = injectFieldAndMarkGenerated(builderType, newField);
|
||||
}
|
||||
if (setFlag == null && bfd.nameOfSetFlag != null) {
|
||||
JCModifiers mods = maker.Modifiers(Flags.PRIVATE);
|
||||
JCVariableDecl newField = maker.VarDef(mods, bfd.nameOfSetFlag, maker.TypeIdent(CTC_BOOLEAN), null);
|
||||
injectFieldAndMarkGenerated(builderType, newField);
|
||||
}
|
||||
bfd.createdFields.add(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generateSetterMethodsForBuilder(final JavacNode builderType, BuilderFieldData fieldNode, JavacNode source, final String builderGenericName) {
|
||||
boolean deprecate = isFieldDeprecated(fieldNode.originalFieldNode);
|
||||
final JavacTreeMaker maker = builderType.getTreeMaker();
|
||||
ExpressionMaker returnTypeMaker = new ExpressionMaker() { @Override public JCExpression make() {
|
||||
return maker.Ident(builderType.toName(builderGenericName));
|
||||
}};
|
||||
|
||||
StatementMaker returnStatementMaker = new StatementMaker() { @Override public JCStatement make() {
|
||||
return maker.Return(maker.Apply(List.<JCExpression>nil(), maker.Ident(builderType.toName(SELF_METHOD)), List.<JCExpression>nil()));
|
||||
}};
|
||||
|
||||
if (fieldNode.singularData == null || fieldNode.singularData.getSingularizer() == null) {
|
||||
generateSimpleSetterMethodForBuilder(builderType, deprecate, fieldNode.createdFields.get(0), fieldNode.nameOfSetFlag, source, true, true, returnTypeMaker.make(), returnStatementMaker.make());
|
||||
} 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) {
|
||||
Name fieldName = ((JCVariableDecl) fieldNode.get()).name;
|
||||
|
||||
for (JavacNode child : builderType.down()) {
|
||||
if (child.getKind() != Kind.METHOD) continue;
|
||||
JCMethodDecl methodDecl = (JCMethodDecl) child.get();
|
||||
Name existingName = methodDecl.name;
|
||||
if (existingName.equals(fieldName) && !isTolerate(fieldNode, methodDecl)) return;
|
||||
}
|
||||
|
||||
String setterName = fluent ? fieldNode.getName() : HandlerUtil.buildAccessorName("set", fieldNode.getName());
|
||||
|
||||
JavacTreeMaker maker = fieldNode.getTreeMaker();
|
||||
|
||||
JCMethodDecl newMethod = HandleSetter.createSetter(Flags.PUBLIC, deprecate, fieldNode, maker, setterName, nameOfSetFlag, returnType, returnStatement, source, List.<JCAnnotation>nil(), List.<JCAnnotation>nil());
|
||||
|
||||
injectMethod(builderType, newMethod);
|
||||
}
|
||||
|
||||
private void addObtainVia(BuilderFieldData bfd, JavacNode node) {
|
||||
for (JavacNode child : node.down()) {
|
||||
if (!annotationTypeMatches(ObtainVia.class, child)) continue;
|
||||
AnnotationValues<ObtainVia> ann = createAnnotation(ObtainVia.class, child);
|
||||
bfd.obtainVia = ann.getInstance();
|
||||
bfd.obtainViaNode = child;
|
||||
deleteAnnotationIfNeccessary(child, ObtainVia.class);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the explicitly requested singular annotation on this node (field
|
||||
* or parameter), or null if there's no {@code @Singular} annotation on it.
|
||||
*
|
||||
* @param node The node (field or method param) to inspect for its name and potential {@code @Singular} annotation.
|
||||
*/
|
||||
private SingularData getSingularData(JavacNode node) {
|
||||
for (JavacNode child : node.down()) {
|
||||
if (!annotationTypeMatches(Singular.class, child)) continue;
|
||||
Name pluralName = node.getKind() == Kind.FIELD ? removePrefixFromField(node) : ((JCVariableDecl) node.get()).name;
|
||||
AnnotationValues<Singular> ann = createAnnotation(Singular.class, child);
|
||||
deleteAnnotationIfNeccessary(child, Singular.class);
|
||||
String explicitSingular = ann.getInstance().value();
|
||||
if (explicitSingular.isEmpty()) {
|
||||
if (Boolean.FALSE.equals(node.getAst().readConfiguration(ConfigurationKeys.SINGULAR_AUTO))) {
|
||||
node.addError("The singular must be specified explicitly (e.g. @Singular(\"task\")) because auto singularization is disabled.");
|
||||
explicitSingular = pluralName.toString();
|
||||
} else {
|
||||
explicitSingular = autoSingularize(pluralName.toString());
|
||||
if (explicitSingular == null) {
|
||||
node.addError("Can't singularize this name; please specify the singular explicitly (i.e. @Singular(\"sheep\"))");
|
||||
explicitSingular = pluralName.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
Name singularName = node.toName(explicitSingular);
|
||||
|
||||
JCExpression type = null;
|
||||
if (node.get() instanceof JCVariableDecl) type = ((JCVariableDecl) node.get()).vartype;
|
||||
|
||||
String name = null;
|
||||
List<JCExpression> typeArgs = List.nil();
|
||||
if (type instanceof JCTypeApply) {
|
||||
typeArgs = ((JCTypeApply) type).arguments;
|
||||
type = ((JCTypeApply) type).clazz;
|
||||
}
|
||||
|
||||
name = type.toString();
|
||||
|
||||
String targetFqn = JavacSingularsRecipes.get().toQualified(name);
|
||||
JavacSingularizer singularizer = JavacSingularsRecipes.get().getSingularizer(targetFqn);
|
||||
if (singularizer == null) {
|
||||
node.addError("Lombok does not know how to create the singular-form builder methods for type '" + name + "'; they won't be generated.");
|
||||
return null;
|
||||
}
|
||||
|
||||
return new SingularData(child, singularName, pluralName, typeArgs, targetFqn, singularizer);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private String generateNonclashingNameFor(String classGenericName, java.util.List<String> typeParamStrings) {
|
||||
if (!typeParamStrings.contains(classGenericName)) return classGenericName;
|
||||
int counter = 2;
|
||||
while (typeParamStrings.contains(classGenericName + counter)) counter++;
|
||||
return classGenericName + counter;
|
||||
}
|
||||
|
||||
private JavacNode findInnerClass(JavacNode parent, String name) {
|
||||
for (JavacNode child : parent.down()) {
|
||||
if (child.getKind() != Kind.TYPE) continue;
|
||||
JCClassDecl td = (JCClassDecl) child.get();
|
||||
if (td.name.contentEquals(name)) return child;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ListBuffer<JCExpression> getTypeParamExpressions(List<? extends JCTree> typeParams, JavacTreeMaker maker) {
|
||||
ListBuffer<JCExpression> typeParamsForBuilderParameter = new ListBuffer<JCExpression>();
|
||||
for (JCTree typeParam : typeParams) {
|
||||
if (typeParam instanceof JCTypeParameter) {
|
||||
typeParamsForBuilderParameter.add(maker.Ident(((JCTypeParameter)typeParam).getName()));
|
||||
} else if (typeParam instanceof JCIdent) {
|
||||
typeParamsForBuilderParameter.add(maker.Ident(((JCIdent)typeParam).getName()));
|
||||
}
|
||||
}
|
||||
return typeParamsForBuilderParameter;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2017 The Project Lombok Authors.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -53,6 +53,14 @@ import com.sun.tools.javac.util.ListBuffer;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
|
||||
public class JavacSingularsRecipes {
|
||||
public interface ExpressionMaker {
|
||||
JCExpression make();
|
||||
}
|
||||
|
||||
public interface StatementMaker {
|
||||
JCStatement make();
|
||||
}
|
||||
|
||||
private static final JavacSingularsRecipes INSTANCE = new JavacSingularsRecipes();
|
||||
private final Map<String, JavacSingularizer> singularizers = new HashMap<String, JavacSingularizer>();
|
||||
private final TypeLibrary singularizableTypes = new TypeLibrary();
|
||||
@@ -194,8 +202,36 @@ public class JavacSingularsRecipes {
|
||||
}
|
||||
|
||||
public abstract java.util.List<JavacNode> generateFields(SingularData data, JavacNode builderType, JCTree source);
|
||||
public abstract void generateMethods(SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, boolean chain);
|
||||
public abstract void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName);
|
||||
|
||||
/**
|
||||
* Generates the singular, plural, and clear methods for the given {@link SingularData}.
|
||||
* Uses the given {@code builderType} as return type if {@code chain == true}, {@code void} otherwise.
|
||||
* If you need more control over the return type and value, use
|
||||
* {@link #generateMethods(SingularData, boolean, JavacNode, JCTree, boolean, ExpressionMaker, StatementMaker)}.
|
||||
*/
|
||||
public void generateMethods(SingularData data, boolean deprecate, final JavacNode builderType, JCTree source, boolean fluent, final boolean chain) {
|
||||
final JavacTreeMaker maker = builderType.getTreeMaker();
|
||||
|
||||
ExpressionMaker returnTypeMaker = new ExpressionMaker() { @Override public JCExpression make() {
|
||||
return chain ?
|
||||
cloneSelfType(builderType) :
|
||||
maker.Type(createVoidType(builderType.getSymbolTable(), CTC_VOID));
|
||||
}};
|
||||
|
||||
StatementMaker returnStatementMaker = new StatementMaker() { @Override public JCStatement make() {
|
||||
return chain ? maker.Return(maker.Ident(builderType.toName("this"))) : null;
|
||||
}};
|
||||
|
||||
generateMethods(data, deprecate, builderType, source, fluent, returnTypeMaker, returnStatementMaker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the singular, plural, and clear methods for the given {@link SingularData}.
|
||||
* Uses the given {@code returnTypeMaker} and {@code returnStatementMaker} for the generated methods.
|
||||
*/
|
||||
public abstract void generateMethods(SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker);
|
||||
|
||||
public abstract void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName, String builderVariable);
|
||||
|
||||
public boolean requiresCleaning() {
|
||||
try {
|
||||
@@ -274,9 +310,9 @@ public class JavacSingularsRecipes {
|
||||
return arguments.toList();
|
||||
}
|
||||
|
||||
/** Generates 'this.<em>name</em>.size()' as an expression; if nullGuard is true, it's this.name == null ? 0 : this.name.size(). */
|
||||
protected JCExpression getSize(JavacTreeMaker maker, JavacNode builderType, Name name, boolean nullGuard, boolean parens) {
|
||||
Name thisName = builderType.toName("this");
|
||||
/** Generates '<em>builderVariable</em>.<em>name</em>.size()' as an expression; if nullGuard is true, it's this.name == null ? 0 : this.name.size(). */
|
||||
protected JCExpression getSize(JavacTreeMaker maker, JavacNode builderType, Name name, boolean nullGuard, boolean parens, String builderVariable) {
|
||||
Name thisName = builderType.toName(builderVariable);
|
||||
JCExpression fn = maker.Select(maker.Select(maker.Ident(thisName), name), builderType.toName("size"));
|
||||
JCExpression sizeInvoke = maker.Apply(List.<JCExpression>nil(), fn, List.<JCExpression>nil());
|
||||
if (nullGuard) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2017 The Project Lombok Authors.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -32,11 +32,12 @@ import lombok.core.handlers.HandlerUtil;
|
||||
import lombok.javac.JavacNode;
|
||||
import lombok.javac.JavacTreeMaker;
|
||||
import lombok.javac.handlers.JavacHandlerUtil;
|
||||
import lombok.javac.handlers.JavacSingularsRecipes.ExpressionMaker;
|
||||
import lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer;
|
||||
import lombok.javac.handlers.JavacSingularsRecipes.SingularData;
|
||||
import lombok.javac.handlers.JavacSingularsRecipes.StatementMaker;
|
||||
|
||||
import com.sun.tools.javac.code.Flags;
|
||||
import com.sun.tools.javac.code.Symtab;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.JCBlock;
|
||||
import com.sun.tools.javac.tree.JCTree.JCExpression;
|
||||
@@ -70,20 +71,11 @@ abstract class JavacGuavaSingularizer extends JavacSingularizer {
|
||||
return Collections.singletonList(injectFieldAndMarkGenerated(builderType, buildField));
|
||||
}
|
||||
|
||||
@Override public void generateMethods(SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, boolean chain) {
|
||||
@Override public void generateMethods(SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker) {
|
||||
JavacTreeMaker maker = builderType.getTreeMaker();
|
||||
Symtab symbolTable = builderType.getSymbolTable();
|
||||
JCExpression returnType = chain ? cloneSelfType(builderType) : maker.Type(createVoidType(symbolTable, CTC_VOID));
|
||||
JCStatement returnStatement = chain ? maker.Return(maker.Ident(builderType.toName("this"))) : null;
|
||||
generateSingularMethod(deprecate, maker, returnType, returnStatement, data, builderType, source, fluent);
|
||||
|
||||
returnType = chain ? cloneSelfType(builderType) : maker.Type(createVoidType(symbolTable, CTC_VOID));
|
||||
returnStatement = chain ? maker.Return(maker.Ident(builderType.toName("this"))) : null;
|
||||
generatePluralMethod(deprecate, maker, returnType, returnStatement, data, builderType, source, fluent);
|
||||
|
||||
returnType = chain ? cloneSelfType(builderType) : maker.Type(createVoidType(symbolTable, CTC_VOID));
|
||||
returnStatement = chain ? maker.Return(maker.Ident(builderType.toName("this"))) : null;
|
||||
generateClearMethod(deprecate, maker, returnType, returnStatement, data, builderType, source);
|
||||
generateSingularMethod(deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source, fluent);
|
||||
generatePluralMethod(deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source, fluent);
|
||||
generateClearMethod(deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source);
|
||||
}
|
||||
|
||||
private void generateClearMethod(boolean deprecate, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source) {
|
||||
@@ -168,7 +160,7 @@ abstract class JavacGuavaSingularizer extends JavacSingularizer {
|
||||
injectMethod(builderType, method);
|
||||
}
|
||||
|
||||
@Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName) {
|
||||
@Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName, String builderVariable) {
|
||||
JavacTreeMaker maker = builderType.getTreeMaker();
|
||||
List<JCExpression> jceBlank = List.nil();
|
||||
|
||||
@@ -185,12 +177,12 @@ abstract class JavacGuavaSingularizer extends JavacSingularizer {
|
||||
|
||||
JCExpression invokeBuild; {
|
||||
//this.pluralName.build();
|
||||
invokeBuild = maker.Apply(jceBlank, chainDots(builderType, "this", data.getPluralName().toString(), "build"), jceBlank);
|
||||
invokeBuild = maker.Apply(jceBlank, chainDots(builderType, builderVariable, data.getPluralName().toString(), "build"), jceBlank);
|
||||
}
|
||||
|
||||
JCExpression isNull; {
|
||||
//this.pluralName == null
|
||||
isNull = maker.Binary(CTC_EQUAL, maker.Select(maker.Ident(builderType.toName("this")), data.getPluralName()), maker.Literal(CTC_BOT, null));
|
||||
isNull = maker.Binary(CTC_EQUAL, maker.Select(maker.Ident(builderType.toName(builderVariable)), data.getPluralName()), maker.Literal(CTC_BOT, null));
|
||||
}
|
||||
|
||||
JCExpression init = maker.Conditional(isNull, empty, invokeBuild); // this.pluralName == null ? ImmutableX.of() : this.pluralName.build()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2017 The Project Lombok Authors.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -30,10 +30,11 @@ import lombok.core.handlers.HandlerUtil;
|
||||
import lombok.javac.JavacNode;
|
||||
import lombok.javac.JavacTreeMaker;
|
||||
import lombok.javac.handlers.JavacHandlerUtil;
|
||||
import lombok.javac.handlers.JavacSingularsRecipes.ExpressionMaker;
|
||||
import lombok.javac.handlers.JavacSingularsRecipes.SingularData;
|
||||
import lombok.javac.handlers.JavacSingularsRecipes.StatementMaker;
|
||||
|
||||
import com.sun.tools.javac.code.Flags;
|
||||
import com.sun.tools.javac.code.Symtab;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.JCBlock;
|
||||
import com.sun.tools.javac.tree.JCTree.JCExpression;
|
||||
@@ -76,27 +77,16 @@ abstract class JavacJavaUtilListSetSingularizer extends JavacJavaUtilSingularize
|
||||
return Collections.singletonList(injectFieldAndMarkGenerated(builderType, buildField));
|
||||
}
|
||||
|
||||
@Override public void generateMethods(SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, boolean chain) {
|
||||
@Override public void generateMethods(SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker) {
|
||||
if (useGuavaInstead(builderType)) {
|
||||
guavaListSetSingularizer.generateMethods(data, deprecate, builderType, source, fluent, chain);
|
||||
guavaListSetSingularizer.generateMethods(data, deprecate, builderType, source, fluent, returnTypeMaker, returnStatementMaker);
|
||||
return;
|
||||
}
|
||||
|
||||
JavacTreeMaker maker = builderType.getTreeMaker();
|
||||
Symtab symbolTable = builderType.getSymbolTable();
|
||||
Name thisName = builderType.toName("this");
|
||||
|
||||
JCExpression returnType = chain ? cloneSelfType(builderType) : maker.Type(createVoidType(symbolTable, CTC_VOID));
|
||||
JCStatement returnStatement = chain ? maker.Return(maker.Ident(thisName)) : null;
|
||||
generateSingularMethod(deprecate, maker, returnType, returnStatement, data, builderType, source, fluent);
|
||||
|
||||
returnType = chain ? cloneSelfType(builderType) : maker.Type(createVoidType(symbolTable, CTC_VOID));
|
||||
returnStatement = chain ? maker.Return(maker.Ident(thisName)) : null;
|
||||
generatePluralMethod(deprecate, maker, returnType, returnStatement, data, builderType, source, fluent);
|
||||
|
||||
returnType = chain ? cloneSelfType(builderType) : maker.Type(createVoidType(symbolTable, CTC_VOID));
|
||||
returnStatement = chain ? maker.Return(maker.Ident(thisName)) : null;
|
||||
generateClearMethod(deprecate, maker, returnType, returnStatement, data, builderType, source);
|
||||
generateSingularMethod(deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source, fluent);
|
||||
generatePluralMethod(deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source, fluent);
|
||||
generateClearMethod(deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source);
|
||||
}
|
||||
|
||||
private void generateClearMethod(boolean deprecate, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source) {
|
||||
|
||||
@@ -46,9 +46,9 @@ public class JavacJavaUtilListSingularizer extends JavacJavaUtilListSetSingulari
|
||||
return LombokImmutableList.of("java.util.List", "java.util.Collection", "java.lang.Iterable");
|
||||
}
|
||||
|
||||
@Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName) {
|
||||
@Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName, String builderVariable) {
|
||||
if (useGuavaInstead(builderType)) {
|
||||
guavaListSetSingularizer.appendBuildCode(data, builderType, source, statements, targetVariableName);
|
||||
guavaListSetSingularizer.appendBuildCode(data, builderType, source, statements, targetVariableName, builderVariable);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ public class JavacJavaUtilListSingularizer extends JavacJavaUtilListSetSingulari
|
||||
JCStatement assignStat; {
|
||||
// pluralName = java.util.Collections.singletonList(this.pluralName.get(0));
|
||||
JCExpression zeroLiteral = maker.Literal(CTC_INT, 0);
|
||||
JCExpression arg = maker.Apply(jceBlank, chainDots(builderType, "this", data.getPluralName().toString(), "get"), List.of(zeroLiteral));
|
||||
JCExpression arg = maker.Apply(jceBlank, chainDots(builderType, builderVariable, data.getPluralName().toString(), "get"), List.of(zeroLiteral));
|
||||
List<JCExpression> args = List.of(arg);
|
||||
JCExpression invoke = maker.Apply(jceBlank, chainDots(builderType, "java", "util", "Collections", "singletonList"), args);
|
||||
assignStat = maker.Exec(maker.Assign(maker.Ident(data.getPluralName()), invoke));
|
||||
@@ -82,12 +82,12 @@ public class JavacJavaUtilListSingularizer extends JavacJavaUtilListSetSingulari
|
||||
}
|
||||
|
||||
/* default: Create with right size, then addAll */ {
|
||||
List<JCStatement> defStats = createListCopy(maker, data, builderType, source);
|
||||
List<JCStatement> defStats = createListCopy(maker, data, builderType, source, builderVariable);
|
||||
JCCase defaultCase = maker.Case(null, defStats);
|
||||
cases.append(defaultCase);
|
||||
}
|
||||
|
||||
JCStatement switchStat = maker.Switch(getSize(maker, builderType, data.getPluralName(), true, false), cases.toList());
|
||||
JCStatement switchStat = maker.Switch(getSize(maker, builderType, data.getPluralName(), true, false, builderVariable), cases.toList());
|
||||
JCExpression localShadowerType = chainDotsString(builderType, data.getTargetFqn());
|
||||
localShadowerType = addTypeArgs(1, false, builderType, localShadowerType, data.getTypeArgs(), source);
|
||||
JCStatement varDefStat = maker.VarDef(maker.Modifiers(0), data.getPluralName(), localShadowerType, null);
|
||||
@@ -95,9 +95,9 @@ public class JavacJavaUtilListSingularizer extends JavacJavaUtilListSetSingulari
|
||||
statements.append(switchStat);
|
||||
}
|
||||
|
||||
private List<JCStatement> createListCopy(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source) {
|
||||
private List<JCStatement> createListCopy(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source, String builderVariable) {
|
||||
List<JCExpression> jceBlank = List.nil();
|
||||
Name thisName = builderType.toName("this");
|
||||
Name thisName = builderType.toName(builderVariable);
|
||||
|
||||
JCExpression argToUnmodifiable; {
|
||||
// new java.util.ArrayList<Generics>(this.pluralName);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2017 The Project Lombok Authors.
|
||||
* Copyright (C) 2015-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
|
||||
@@ -31,13 +31,14 @@ import lombok.core.handlers.HandlerUtil;
|
||||
import lombok.javac.JavacNode;
|
||||
import lombok.javac.JavacTreeMaker;
|
||||
import lombok.javac.handlers.JavacHandlerUtil;
|
||||
import lombok.javac.handlers.JavacSingularsRecipes.ExpressionMaker;
|
||||
import lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer;
|
||||
import lombok.javac.handlers.JavacSingularsRecipes.SingularData;
|
||||
import lombok.javac.handlers.JavacSingularsRecipes.StatementMaker;
|
||||
|
||||
import org.mangosdk.spi.ProviderFor;
|
||||
|
||||
import com.sun.tools.javac.code.Flags;
|
||||
import com.sun.tools.javac.code.Symtab;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.JCBlock;
|
||||
import com.sun.tools.javac.tree.JCTree.JCExpression;
|
||||
@@ -101,26 +102,16 @@ public class JavacJavaUtilMapSingularizer extends JavacJavaUtilSingularizer {
|
||||
return Arrays.asList(keyFieldNode, valueFieldNode);
|
||||
}
|
||||
|
||||
@Override public void generateMethods(SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, boolean chain) {
|
||||
@Override public void generateMethods(SingularData data, boolean deprecate, JavacNode builderType, JCTree source, boolean fluent, ExpressionMaker returnTypeMaker, StatementMaker returnStatementMaker) {
|
||||
if (useGuavaInstead(builderType)) {
|
||||
guavaMapSingularizer.generateMethods(data, deprecate, builderType, source, fluent, chain);
|
||||
guavaMapSingularizer.generateMethods(data, deprecate, builderType, source, fluent, returnTypeMaker, returnStatementMaker);
|
||||
return;
|
||||
}
|
||||
|
||||
JavacTreeMaker maker = builderType.getTreeMaker();
|
||||
Symtab symbolTable = builderType.getSymbolTable();
|
||||
|
||||
JCExpression returnType = chain ? cloneSelfType(builderType) : maker.Type(createVoidType(symbolTable, CTC_VOID));
|
||||
JCStatement returnStatement = chain ? maker.Return(maker.Ident(builderType.toName("this"))) : null;
|
||||
generateSingularMethod(deprecate, maker, returnType, returnStatement, data, builderType, source, fluent);
|
||||
|
||||
returnType = chain ? cloneSelfType(builderType) : maker.Type(createVoidType(symbolTable, CTC_VOID));
|
||||
returnStatement = chain ? maker.Return(maker.Ident(builderType.toName("this"))) : null;
|
||||
generatePluralMethod(deprecate, maker, returnType, returnStatement, data, builderType, source, fluent);
|
||||
|
||||
returnType = chain ? cloneSelfType(builderType) : maker.Type(createVoidType(symbolTable, CTC_VOID));
|
||||
returnStatement = chain ? maker.Return(maker.Ident(builderType.toName("this"))) : null;
|
||||
generateClearMethod(deprecate, maker, returnType, returnStatement, data, builderType, source);
|
||||
generateSingularMethod(deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source, fluent);
|
||||
generatePluralMethod(deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source, fluent);
|
||||
generateClearMethod(deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source);
|
||||
}
|
||||
|
||||
private void generateClearMethod(boolean deprecate, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source) {
|
||||
@@ -212,18 +203,18 @@ public class JavacJavaUtilMapSingularizer extends JavacJavaUtilSingularizer {
|
||||
injectMethod(builderType, method);
|
||||
}
|
||||
|
||||
@Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName) {
|
||||
@Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName, String builderVariable) {
|
||||
if (useGuavaInstead(builderType)) {
|
||||
guavaMapSingularizer.appendBuildCode(data, builderType, source, statements, targetVariableName);
|
||||
guavaMapSingularizer.appendBuildCode(data, builderType, source, statements, targetVariableName, builderVariable);
|
||||
return;
|
||||
}
|
||||
|
||||
JavacTreeMaker maker = builderType.getTreeMaker();
|
||||
|
||||
if (data.getTargetFqn().equals("java.util.Map")) {
|
||||
statements.appendList(createJavaUtilSetMapInitialCapacitySwitchStatements(maker, data, builderType, true, "emptyMap", "singletonMap", "LinkedHashMap", source));
|
||||
statements.appendList(createJavaUtilSetMapInitialCapacitySwitchStatements(maker, data, builderType, true, "emptyMap", "singletonMap", "LinkedHashMap", source, builderVariable));
|
||||
} else {
|
||||
statements.appendList(createJavaUtilSimpleCreationAndFillStatements(maker, data, builderType, true, true, false, true, "TreeMap", source));
|
||||
statements.appendList(createJavaUtilSimpleCreationAndFillStatements(maker, data, builderType, true, true, false, true, "TreeMap", source, builderVariable));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,18 +40,18 @@ public class JavacJavaUtilSetSingularizer extends JavacJavaUtilListSetSingulariz
|
||||
return LombokImmutableList.of("java.util.Set", "java.util.SortedSet", "java.util.NavigableSet");
|
||||
}
|
||||
|
||||
@Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName) {
|
||||
@Override public void appendBuildCode(SingularData data, JavacNode builderType, JCTree source, ListBuffer<JCStatement> statements, Name targetVariableName, String builderVariable) {
|
||||
if (useGuavaInstead(builderType)) {
|
||||
guavaListSetSingularizer.appendBuildCode(data, builderType, source, statements, targetVariableName);
|
||||
guavaListSetSingularizer.appendBuildCode(data, builderType, source, statements, targetVariableName, builderVariable);
|
||||
return;
|
||||
}
|
||||
|
||||
JavacTreeMaker maker = builderType.getTreeMaker();
|
||||
|
||||
if (data.getTargetFqn().equals("java.util.Set")) {
|
||||
statements.appendList(createJavaUtilSetMapInitialCapacitySwitchStatements(maker, data, builderType, false, "emptySet", "singleton", "LinkedHashSet", source));
|
||||
statements.appendList(createJavaUtilSetMapInitialCapacitySwitchStatements(maker, data, builderType, false, "emptySet", "singleton", "LinkedHashSet", source, builderVariable));
|
||||
} else {
|
||||
statements.appendList(createJavaUtilSimpleCreationAndFillStatements(maker, data, builderType, false, true, false, true, "TreeSet", source));
|
||||
statements.appendList(createJavaUtilSimpleCreationAndFillStatements(maker, data, builderType, false, true, false, true, "TreeSet", source, builderVariable));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer {
|
||||
return Boolean.TRUE.equals(node.getAst().readConfiguration(ConfigurationKeys.SINGULAR_USE_GUAVA));
|
||||
}
|
||||
|
||||
protected List<JCStatement> createJavaUtilSetMapInitialCapacitySwitchStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, boolean mapMode, String emptyCollectionMethod, String singletonCollectionMethod, String targetType, JCTree source) {
|
||||
protected List<JCStatement> createJavaUtilSetMapInitialCapacitySwitchStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, boolean mapMode, String emptyCollectionMethod, String singletonCollectionMethod, String targetType, JCTree source, String builderVariable) {
|
||||
List<JCExpression> jceBlank = List.nil();
|
||||
ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
|
||||
|
||||
@@ -66,11 +66,11 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer {
|
||||
// !mapMode: pluralName = java.util.Collections.singletonCollectionMethod(this.pluralName.get(0));
|
||||
// mapMode: pluralName = java.util.Collections.singletonCollectionMethod(this.pluralName$key.get(0), this.pluralName$value.get(0));
|
||||
JCExpression zeroLiteral = maker.Literal(CTC_INT, 0);
|
||||
JCExpression arg = maker.Apply(jceBlank, chainDots(builderType, "this", data.getPluralName() + (mapMode ? "$key" : ""), "get"), List.of(zeroLiteral));
|
||||
JCExpression arg = maker.Apply(jceBlank, chainDots(builderType, builderVariable, data.getPluralName() + (mapMode ? "$key" : ""), "get"), List.of(zeroLiteral));
|
||||
List<JCExpression> args;
|
||||
if (mapMode) {
|
||||
JCExpression zeroLiteralClone = maker.Literal(CTC_INT, 0);
|
||||
JCExpression arg2 = maker.Apply(jceBlank, chainDots(builderType, "this", data.getPluralName() + (mapMode ? "$value" : ""), "get"), List.of(zeroLiteralClone));
|
||||
JCExpression arg2 = maker.Apply(jceBlank, chainDots(builderType, builderVariable, data.getPluralName() + (mapMode ? "$value" : ""), "get"), List.of(zeroLiteralClone));
|
||||
args = List.of(arg, arg2);
|
||||
} else {
|
||||
args = List.of(arg);
|
||||
@@ -84,12 +84,12 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer {
|
||||
}
|
||||
|
||||
{ // default:
|
||||
List<JCStatement> statements = createJavaUtilSimpleCreationAndFillStatements(maker, data, builderType, mapMode, false, true, emptyCollectionMethod == null, targetType, source);
|
||||
List<JCStatement> statements = createJavaUtilSimpleCreationAndFillStatements(maker, data, builderType, mapMode, false, true, emptyCollectionMethod == null, targetType, source, builderVariable);
|
||||
JCCase defaultCase = maker.Case(null, statements);
|
||||
cases.append(defaultCase);
|
||||
}
|
||||
|
||||
JCStatement switchStat = maker.Switch(getSize(maker, builderType, mapMode ? builderType.toName(data.getPluralName() + "$key") : data.getPluralName(), true, false), cases.toList());
|
||||
JCStatement switchStat = maker.Switch(getSize(maker, builderType, mapMode ? builderType.toName(data.getPluralName() + "$key") : data.getPluralName(), true, false, builderVariable), cases.toList());
|
||||
JCExpression localShadowerType = chainDotsString(builderType, data.getTargetFqn());
|
||||
localShadowerType = addTypeArgs(mapMode ? 2 : 1, false, builderType, localShadowerType, data.getTypeArgs(), source);
|
||||
JCStatement varDefStat = maker.VarDef(maker.Modifiers(0), data.getPluralName(), localShadowerType, null);
|
||||
@@ -125,9 +125,9 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer {
|
||||
return maker.If(cond, thenPart, null);
|
||||
}
|
||||
|
||||
protected List<JCStatement> createJavaUtilSimpleCreationAndFillStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, boolean mapMode, boolean defineVar, boolean addInitialCapacityArg, boolean nullGuard, String targetType, JCTree source) {
|
||||
protected List<JCStatement> createJavaUtilSimpleCreationAndFillStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, boolean mapMode, boolean defineVar, boolean addInitialCapacityArg, boolean nullGuard, String targetType, JCTree source, String builderVariable) {
|
||||
List<JCExpression> jceBlank = List.nil();
|
||||
Name thisName = builderType.toName("this");
|
||||
Name thisName = builderType.toName(builderVariable);
|
||||
|
||||
JCStatement createStat; {
|
||||
// pluralName = new java.util.TargetType(initialCap);
|
||||
@@ -136,10 +136,10 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer {
|
||||
Name varName = mapMode ? builderType.toName(data.getPluralName() + "$key") : data.getPluralName();
|
||||
// this.varName.size() < MAX_POWER_OF_2 ? 1 + this.varName.size() + (this.varName.size() - 3) / 3 : Integer.MAX_VALUE;
|
||||
// lessThanCutOff = this.varName.size() < MAX_POWER_OF_2
|
||||
JCExpression lessThanCutoff = maker.Binary(CTC_LESS_THAN, getSize(maker, builderType, varName, nullGuard, true), maker.Literal(CTC_INT, 0x40000000));
|
||||
JCExpression lessThanCutoff = maker.Binary(CTC_LESS_THAN, getSize(maker, builderType, varName, nullGuard, true, builderVariable), maker.Literal(CTC_INT, 0x40000000));
|
||||
JCExpression integerMaxValue = genJavaLangTypeRef(builderType, "Integer", "MAX_VALUE");
|
||||
JCExpression sizeFormulaLeft = maker.Binary(CTC_PLUS, maker.Literal(CTC_INT, 1), getSize(maker, builderType, varName, nullGuard, true));
|
||||
JCExpression sizeFormulaRightLeft = maker.Parens(maker.Binary(CTC_MINUS, getSize(maker, builderType, varName, nullGuard, true), maker.Literal(CTC_INT, 3)));
|
||||
JCExpression sizeFormulaLeft = maker.Binary(CTC_PLUS, maker.Literal(CTC_INT, 1), getSize(maker, builderType, varName, nullGuard, true, builderVariable));
|
||||
JCExpression sizeFormulaRightLeft = maker.Parens(maker.Binary(CTC_MINUS, getSize(maker, builderType, varName, nullGuard, true, builderVariable), maker.Literal(CTC_INT, 3)));
|
||||
JCExpression sizeFormulaRight = maker.Binary(CTC_DIV, sizeFormulaRightLeft, maker.Literal(CTC_INT, 3));
|
||||
JCExpression sizeFormula = maker.Binary(CTC_PLUS, sizeFormulaLeft, sizeFormulaRight);
|
||||
constructorArgs = List.<JCExpression>of(maker.Conditional(lessThanCutoff, sizeFormula, integerMaxValue));
|
||||
@@ -163,14 +163,14 @@ abstract class JavacJavaUtilSingularizer extends JavacSingularizer {
|
||||
Name ivar = builderType.toName("$i");
|
||||
Name keyVarName = builderType.toName(data.getPluralName() + "$key");
|
||||
JCExpression pluralnameDotPut = maker.Select(maker.Ident(data.getPluralName()), builderType.toName("put"));
|
||||
JCExpression arg1 = maker.Apply(jceBlank, chainDots(builderType, "this", data.getPluralName() + "$key", "get"), List.<JCExpression>of(maker.Ident(ivar)));
|
||||
JCExpression arg2 = maker.Apply(jceBlank, chainDots(builderType, "this", data.getPluralName() + "$value", "get"), List.<JCExpression>of(maker.Ident(ivar)));
|
||||
JCExpression arg1 = maker.Apply(jceBlank, chainDots(builderType, builderVariable, data.getPluralName() + "$key", "get"), List.<JCExpression>of(maker.Ident(ivar)));
|
||||
JCExpression arg2 = maker.Apply(jceBlank, chainDots(builderType, builderVariable, data.getPluralName() + "$value", "get"), List.<JCExpression>of(maker.Ident(ivar)));
|
||||
// [jdk9] We add an unneccessary (V) cast here. Not doing so gives an error in javac (build 9-ea+156-jigsaw-nightly-h6072-20170212):
|
||||
// error: method put in interface Map<K#2,V#2> cannot be applied to given types;
|
||||
arg2 = maker.TypeCast(createTypeArgs(2, false, builderType, data.getTypeArgs(), source).get(1), arg2);
|
||||
JCStatement putStatement = maker.Exec(maker.Apply(jceBlank, pluralnameDotPut, List.of(arg1, arg2)));
|
||||
JCStatement forInit = maker.VarDef(maker.Modifiers(0), ivar, maker.TypeIdent(CTC_INT), maker.Literal(CTC_INT, 0));
|
||||
JCExpression checkExpr = maker.Binary(CTC_LESS_THAN, maker.Ident(ivar), getSize(maker, builderType, keyVarName, nullGuard, true));
|
||||
JCExpression checkExpr = maker.Binary(CTC_LESS_THAN, maker.Ident(ivar), getSize(maker, builderType, keyVarName, nullGuard, true, builderVariable));
|
||||
JCExpression incrementExpr = maker.Unary(CTC_POSTINC, maker.Ident(ivar));
|
||||
fillStat = maker.ForLoop(List.of(forInit), checkExpr, List.of(maker.Exec(incrementExpr)), putStatement);
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
public class SuperBuilderAbstract {
|
||||
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 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 "SuperBuilderAbstract.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();
|
||||
}
|
||||
}
|
||||
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 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 "SuperBuilderAbstract.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 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 "SuperBuilderAbstract.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();
|
||||
}
|
||||
}
|
||||
public static void test() {
|
||||
GrandChild x = GrandChild.builder().grandChildField("").parentField(5).childField(2.5).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
import java.util.List;
|
||||
public class SuperBuilderBasic {
|
||||
public static class Parent {
|
||||
int field1;
|
||||
List<String> items;
|
||||
@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 java.util.ArrayList<String> 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 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 "SuperBuilderBasic.Parent.ParentBuilder(field1=" + this.field1 + ", 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;
|
||||
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();
|
||||
}
|
||||
}
|
||||
public static class Child extends Parent {
|
||||
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 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 "SuperBuilderBasic.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();
|
||||
}
|
||||
}
|
||||
public static void test() {
|
||||
Child x = Child.builder().field3(0.0).field1(5).item("").build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
import java.util.List;
|
||||
public class SuperBuilderWithCustomBuilderMethod {
|
||||
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 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 "SuperBuilderWithCustomBuilderMethod.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 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>();
|
||||
}
|
||||
}
|
||||
public static class Child<A> extends Parent<A> {
|
||||
double field3;
|
||||
public static <A> ChildBuilder<A, ?, ?> builder() {
|
||||
return new ChildBuilderImpl<A>().item("default item");
|
||||
}
|
||||
@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 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 "SuperBuilderWithCustomBuilderMethod.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 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;
|
||||
}
|
||||
}
|
||||
public static void test() {
|
||||
Child<Integer> x = Child.<Integer>builder().field3(0.0).field1(5).item("").build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
import java.util.List;
|
||||
public class SuperBuilderWithDefaults {
|
||||
public static class Parent<N extends Number> {
|
||||
private long millis = System.currentTimeMillis();
|
||||
private N numberField = null;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static abstract class ParentBuilder<N extends Number, C extends Parent<N>, B extends ParentBuilder<N, C, B>> {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private boolean millis$set;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private long millis;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private boolean numberField$set;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private N numberField;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected abstract B self();
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public abstract C build();
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B millis(final long millis) {
|
||||
this.millis = millis;
|
||||
millis$set = true;
|
||||
return self();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B numberField(final N numberField) {
|
||||
this.numberField = numberField;
|
||||
numberField$set = true;
|
||||
return self();
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public java.lang.String toString() {
|
||||
return "SuperBuilderWithDefaults.Parent.ParentBuilder(millis=" + this.millis + ", numberField=" + this.numberField + ")";
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private static final class ParentBuilderImpl<N extends Number> extends ParentBuilder<N, Parent<N>, ParentBuilderImpl<N>> {
|
||||
@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<N> build() {
|
||||
return new Parent<N>(this);
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected Parent(final ParentBuilder<N, ?, ?> b) {
|
||||
if (b.millis$set) this.millis = b.millis;
|
||||
if (b.numberField$set) this.numberField = b.numberField;
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static <N extends Number> ParentBuilder<N, ?, ?> builder() {
|
||||
return new ParentBuilderImpl<N>();
|
||||
}
|
||||
}
|
||||
public static class Child extends Parent<Integer> {
|
||||
private double doubleField = Math.PI;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static abstract class ChildBuilder<C extends Child, B extends ChildBuilder<C, B>> extends Parent.ParentBuilder<Integer, C, B> {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private boolean doubleField$set;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private double doubleField;
|
||||
@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 doubleField(final double doubleField) {
|
||||
this.doubleField = doubleField;
|
||||
doubleField$set = true;
|
||||
return self();
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public java.lang.String toString() {
|
||||
return "SuperBuilderWithDefaults.Child.ChildBuilder(super=" + super.toString() + ", doubleField=" + this.doubleField + ")";
|
||||
}
|
||||
}
|
||||
@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);
|
||||
if (b.doubleField$set) this.doubleField = b.doubleField;
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static ChildBuilder<?, ?> builder() {
|
||||
return new ChildBuilderImpl();
|
||||
}
|
||||
}
|
||||
public static void test() {
|
||||
Child x = Child.builder().doubleField(0.1).numberField(5).millis(1234567890L).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
import java.util.List;
|
||||
public class SuperBuilderWithGenerics {
|
||||
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 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 "SuperBuilderWithGenerics.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 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>();
|
||||
}
|
||||
}
|
||||
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 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 "SuperBuilderWithGenerics.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 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>();
|
||||
}
|
||||
}
|
||||
public static void test() {
|
||||
Child<Integer> x = Child.<Integer>builder().field3(0.0).field1(5).item("").build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
import java.util.List;
|
||||
public class SuperBuilderWithGenerics2 {
|
||||
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 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 "SuperBuilderWithGenerics2.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 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>();
|
||||
}
|
||||
}
|
||||
public static class Child<A> extends Parent<String> {
|
||||
A field3;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static abstract class ChildBuilder<A, C extends Child<A>, B extends ChildBuilder<A, C, B>> extends Parent.ParentBuilder<String, C, B> {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private A 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 A field3) {
|
||||
this.field3 = field3;
|
||||
return self();
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public java.lang.String toString() {
|
||||
return "SuperBuilderWithGenerics2.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 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, ?, ?> builder2() {
|
||||
return new ChildBuilderImpl<A>();
|
||||
}
|
||||
}
|
||||
public static void test() {
|
||||
Child<Integer> x = Child.<Integer>builder2().field3(1).field1("value").item("").build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
public class SuperBuilderAbstract {
|
||||
public static @lombok.experimental.SuperBuilder 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 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 (("SuperBuilderAbstract.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 static @java.lang.SuppressWarnings("all") ParentBuilder<?, ?> builder() {
|
||||
return new ParentBuilderImpl();
|
||||
}
|
||||
}
|
||||
public static abstract @lombok.experimental.SuperBuilder 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 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 (((("SuperBuilderAbstract.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 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 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 (((("SuperBuilderAbstract.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 static @java.lang.SuppressWarnings("all") GrandChildBuilder<?, ?> builder() {
|
||||
return new GrandChildBuilderImpl();
|
||||
}
|
||||
}
|
||||
public SuperBuilderAbstract() {
|
||||
super();
|
||||
}
|
||||
public static void test() {
|
||||
GrandChild x = GrandChild.builder().grandChildField("").parentField(5).childField(2.5).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
import java.util.List;
|
||||
public class SuperBuilderBasic {
|
||||
public static @lombok.experimental.SuperBuilder class Parent {
|
||||
public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder<C extends Parent, B extends ParentBuilder<C, B>> {
|
||||
private @java.lang.SuppressWarnings("all") int field1;
|
||||
private @java.lang.SuppressWarnings("all") java.util.ArrayList<String> items;
|
||||
public ParentBuilder() {
|
||||
super();
|
||||
}
|
||||
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 item(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(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 (((("SuperBuilderBasic.Parent.ParentBuilder(field1=" + this.field1) + ", 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);
|
||||
}
|
||||
}
|
||||
int field1;
|
||||
@lombok.Singular List<String> items;
|
||||
protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder<?, ?> 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 static @java.lang.SuppressWarnings("all") ParentBuilder<?, ?> builder() {
|
||||
return new ParentBuilderImpl();
|
||||
}
|
||||
}
|
||||
public static @lombok.experimental.SuperBuilder 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 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 (((("SuperBuilderBasic.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);
|
||||
}
|
||||
}
|
||||
double field3;
|
||||
protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder<?, ?> b) {
|
||||
super(b);
|
||||
this.field3 = b.field3;
|
||||
}
|
||||
public static @java.lang.SuppressWarnings("all") ChildBuilder<?, ?> builder() {
|
||||
return new ChildBuilderImpl();
|
||||
}
|
||||
}
|
||||
public SuperBuilderBasic() {
|
||||
super();
|
||||
}
|
||||
public static void test() {
|
||||
Child x = Child.builder().field3(0.0).field1(5).item("").build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
import java.util.List;
|
||||
public class SuperBuilderWithCustomBuilderMethod {
|
||||
public static @lombok.experimental.SuperBuilder 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 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(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(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 (((("SuperBuilderWithCustomBuilderMethod.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 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 static @java.lang.SuppressWarnings("all") <A>ParentBuilder<A, ?, ?> builder() {
|
||||
return new ParentBuilderImpl<A>();
|
||||
}
|
||||
}
|
||||
public static @lombok.experimental.SuperBuilder 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 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 (((("SuperBuilderWithCustomBuilderMethod.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 self() {
|
||||
return this;
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") Child<A> build() {
|
||||
return new Child<A>(this);
|
||||
}
|
||||
}
|
||||
double field3;
|
||||
public static <A>ChildBuilder<A, ?, ?> builder() {
|
||||
return new ChildBuilderImpl<A>().item("default item");
|
||||
}
|
||||
protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder<A, ?, ?> b) {
|
||||
super(b);
|
||||
this.field3 = b.field3;
|
||||
}
|
||||
}
|
||||
public SuperBuilderWithCustomBuilderMethod() {
|
||||
super();
|
||||
}
|
||||
public static void test() {
|
||||
Child<Integer> x = Child.<Integer>builder().field3(0.0).field1(5).item("").build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import java.util.List;
|
||||
public class SuperBuilderWithDefaults {
|
||||
public static @lombok.experimental.SuperBuilder class Parent<N extends Number> {
|
||||
public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder<N extends Number, C extends Parent<N>, B extends ParentBuilder<N, C, B>> {
|
||||
private @java.lang.SuppressWarnings("all") long millis;
|
||||
private @java.lang.SuppressWarnings("all") boolean millis$set;
|
||||
private @java.lang.SuppressWarnings("all") N numberField;
|
||||
private @java.lang.SuppressWarnings("all") boolean numberField$set;
|
||||
public ParentBuilder() {
|
||||
super();
|
||||
}
|
||||
protected abstract @java.lang.SuppressWarnings("all") B self();
|
||||
public abstract @java.lang.SuppressWarnings("all") C build();
|
||||
public @java.lang.SuppressWarnings("all") B millis(final long millis) {
|
||||
this.millis = millis;
|
||||
millis$set = true;
|
||||
return self();
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") B numberField(final N numberField) {
|
||||
this.numberField = numberField;
|
||||
numberField$set = true;
|
||||
return self();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
|
||||
return (((("SuperBuilderWithDefaults.Parent.ParentBuilder(millis=" + this.millis) + ", numberField=") + this.numberField) + ")");
|
||||
}
|
||||
}
|
||||
private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl<N extends Number> extends ParentBuilder<N, Parent<N>, ParentBuilderImpl<N>> {
|
||||
private ParentBuilderImpl() {
|
||||
super();
|
||||
}
|
||||
protected @java.lang.Override @java.lang.SuppressWarnings("all") ParentBuilderImpl self() {
|
||||
return this;
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") Parent<N> build() {
|
||||
return new Parent<N>(this);
|
||||
}
|
||||
}
|
||||
private @lombok.Builder.Default long millis = System.currentTimeMillis();
|
||||
private @lombok.Builder.Default N numberField = null;
|
||||
protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder<N, ?, ?> b) {
|
||||
super();
|
||||
if (b.millis$set)
|
||||
this.millis = b.millis;
|
||||
if (b.numberField$set)
|
||||
this.numberField = b.numberField;
|
||||
}
|
||||
public static @java.lang.SuppressWarnings("all") <N extends Number>ParentBuilder<N, ?, ?> builder() {
|
||||
return new ParentBuilderImpl<N>();
|
||||
}
|
||||
}
|
||||
public static @lombok.experimental.SuperBuilder class Child extends Parent<Integer> {
|
||||
public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder<C extends Child, B extends ChildBuilder<C, B>> extends Parent.ParentBuilder<Integer, C, B> {
|
||||
private @java.lang.SuppressWarnings("all") double doubleField;
|
||||
private @java.lang.SuppressWarnings("all") boolean doubleField$set;
|
||||
public ChildBuilder() {
|
||||
super();
|
||||
}
|
||||
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 doubleField(final double doubleField) {
|
||||
this.doubleField = doubleField;
|
||||
doubleField$set = true;
|
||||
return self();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
|
||||
return (((("SuperBuilderWithDefaults.Child.ChildBuilder(super=" + super.toString()) + ", doubleField=") + this.doubleField) + ")");
|
||||
}
|
||||
}
|
||||
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 @lombok.Builder.Default double doubleField = Math.PI;
|
||||
protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder<?, ?> b) {
|
||||
super(b);
|
||||
if (b.doubleField$set)
|
||||
this.doubleField = b.doubleField;
|
||||
}
|
||||
public static @java.lang.SuppressWarnings("all") ChildBuilder<?, ?> builder() {
|
||||
return new ChildBuilderImpl();
|
||||
}
|
||||
}
|
||||
public SuperBuilderWithDefaults() {
|
||||
super();
|
||||
}
|
||||
public static void test() {
|
||||
Child x = Child.builder().doubleField(0.1).numberField(5).millis(1234567890L).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
import java.util.List;
|
||||
public class SuperBuilderWithGenerics {
|
||||
public static @lombok.experimental.SuperBuilder 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 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(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(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 (((("SuperBuilderWithGenerics.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 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 static @java.lang.SuppressWarnings("all") <A>ParentBuilder<A, ?, ?> builder() {
|
||||
return new ParentBuilderImpl<A>();
|
||||
}
|
||||
}
|
||||
public static @lombok.experimental.SuperBuilder 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 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 (((("SuperBuilderWithGenerics.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 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 static @java.lang.SuppressWarnings("all") <A>ChildBuilder<A, ?, ?> builder() {
|
||||
return new ChildBuilderImpl<A>();
|
||||
}
|
||||
}
|
||||
public SuperBuilderWithGenerics() {
|
||||
super();
|
||||
}
|
||||
public static void test() {
|
||||
Child<Integer> x = Child.<Integer>builder().field3(0.0).field1(5).item("").build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
import java.util.List;
|
||||
public class SuperBuilderWithGenerics2 {
|
||||
public static @lombok.experimental.SuperBuilder 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 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(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(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 (((("SuperBuilderWithGenerics2.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 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 static @java.lang.SuppressWarnings("all") <A>ParentBuilder<A, ?, ?> builder() {
|
||||
return new ParentBuilderImpl<A>();
|
||||
}
|
||||
}
|
||||
public static @lombok.experimental.SuperBuilder(builderMethodName = "builder2") class Child<A> extends Parent<String> {
|
||||
public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder<A, C extends Child<A>, B extends ChildBuilder<A, C, B>> extends Parent.ParentBuilder<String, C, B> {
|
||||
private @java.lang.SuppressWarnings("all") A field3;
|
||||
public ChildBuilder() {
|
||||
super();
|
||||
}
|
||||
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 A field3) {
|
||||
this.field3 = field3;
|
||||
return self();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
|
||||
return (((("SuperBuilderWithGenerics2.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 self() {
|
||||
return this;
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") Child<A> build() {
|
||||
return new Child<A>(this);
|
||||
}
|
||||
}
|
||||
A field3;
|
||||
protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder<A, ?, ?> b) {
|
||||
super(b);
|
||||
this.field3 = b.field3;
|
||||
}
|
||||
public static @java.lang.SuppressWarnings("all") <A>ChildBuilder<A, ?, ?> builder2() {
|
||||
return new ChildBuilderImpl<A>();
|
||||
}
|
||||
}
|
||||
public SuperBuilderWithGenerics2() {
|
||||
super();
|
||||
}
|
||||
public static void test() {
|
||||
Child<Integer> x = Child.<Integer>builder2().field3(1).field1("value").item("").build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
public class SuperBuilderAbstract {
|
||||
@lombok.experimental.SuperBuilder
|
||||
public static class Parent {
|
||||
int parentField;
|
||||
}
|
||||
|
||||
@lombok.experimental.SuperBuilder
|
||||
public abstract static class Child extends Parent {
|
||||
double childField;
|
||||
}
|
||||
|
||||
@lombok.experimental.SuperBuilder
|
||||
public static class GrandChild extends Child {
|
||||
String grandChildField;
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
GrandChild x = GrandChild.builder().grandChildField("").parentField(5).childField(2.5).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import java.util.List;
|
||||
|
||||
public class SuperBuilderBasic {
|
||||
@lombok.experimental.SuperBuilder
|
||||
public static class Parent {
|
||||
int field1;
|
||||
@lombok.Singular List<String> items;
|
||||
}
|
||||
|
||||
@lombok.experimental.SuperBuilder
|
||||
public static class Child extends Parent {
|
||||
double field3;
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
Child x = Child.builder().field3(0.0).field1(5).item("").build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import java.util.List;
|
||||
|
||||
public class SuperBuilderWithCustomBuilderMethod {
|
||||
@lombok.experimental.SuperBuilder
|
||||
public static class Parent<A> {
|
||||
A field1;
|
||||
@lombok.Singular List<String> items;
|
||||
}
|
||||
|
||||
@lombok.experimental.SuperBuilder
|
||||
public static class Child<A> extends Parent<A> {
|
||||
double field3;
|
||||
public static <A> ChildBuilder<A, ?, ?> builder() {
|
||||
return new ChildBuilderImpl<A>().item("default item");
|
||||
}
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
Child<Integer> x = Child.<Integer>builder().field3(0.0).field1(5).item("").build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import java.util.List;
|
||||
|
||||
public class SuperBuilderWithDefaults {
|
||||
@lombok.experimental.SuperBuilder
|
||||
public static class Parent<N extends Number> {
|
||||
@lombok.Builder.Default private long millis = System.currentTimeMillis();
|
||||
@lombok.Builder.Default private N numberField = null;
|
||||
}
|
||||
|
||||
@lombok.experimental.SuperBuilder
|
||||
public static class Child extends Parent<Integer> {
|
||||
@lombok.Builder.Default private double doubleField = Math.PI;
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
Child x = Child.builder().doubleField(0.1).numberField(5).millis(1234567890L).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import java.util.List;
|
||||
|
||||
public class SuperBuilderWithGenerics {
|
||||
@lombok.experimental.SuperBuilder
|
||||
public static class Parent<A> {
|
||||
A field1;
|
||||
@lombok.Singular List<String> items;
|
||||
}
|
||||
|
||||
@lombok.experimental.SuperBuilder
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import java.util.List;
|
||||
|
||||
public class SuperBuilderWithGenerics2 {
|
||||
@lombok.experimental.SuperBuilder
|
||||
public static class Parent<A> {
|
||||
A field1;
|
||||
@lombok.Singular List<String> items;
|
||||
}
|
||||
|
||||
@lombok.experimental.SuperBuilder(builderMethodName="builder2")
|
||||
public static class Child<A> extends Parent<String> {
|
||||
A field3;
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
Child<Integer> x = Child.<Integer>builder2().field3(1).field1("value").item("").build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<#import "_features.html" as f>
|
||||
|
||||
<@f.scaffold title="@SuperBuilder" logline="Bob now knows his ancestors: Builders with fields from superclasses, too. ">
|
||||
<@f.history>
|
||||
<p>
|
||||
<code>@SuperBuilder</code> was introduced as experimental feature in lombok v1.18.2.
|
||||
</p>
|
||||
</@f.history>
|
||||
|
||||
<@f.overview>
|
||||
<p>
|
||||
The <code>@SuperBuilder</code> annotation produces complex builder APIs for your classes.
|
||||
In contrast to <a href="/features/Builder"><code>@Builder</code></a>, <code>@SuperBuilder</code> also works with fields from superclasses.
|
||||
However, it only works for types, and cannot be customized by providing a partial builder implementation.
|
||||
Most importantly, it requires that <em>all superclasses</em> also have the <code>@SuperBuilder</code> annotation.
|
||||
</p><p>
|
||||
<code>@SuperBuilder</code> lets you automatically produce the code required to have your class be instantiable with code such as:<br />
|
||||
<code>Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build();</code>
|
||||
</p><p>
|
||||
<code>@SuperBuilder</code> can generate so-called 'singular' methods for collection parameters/fields. For details, see <a href="/features/Builder#singular">the <code>@Singular</code> documentation in <code>@Builder</code></a>.
|
||||
</p><p>
|
||||
<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>
|
||||
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>
|
||||
The configurable aspects of builder are:
|
||||
<ul>
|
||||
<li>
|
||||
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>
|
||||
</ul>
|
||||
Example usage where all options are changed from their defaults:<br />
|
||||
<code>@SuperBuilder(buildMethodName = "execute", builderMethodName = "helloWorld")</code><br />
|
||||
</p>
|
||||
</@f.overview>
|
||||
|
||||
<@f.confKeys>
|
||||
<dt>
|
||||
<code>lombok.superBuilder.flagUsage</code> = [<code>warning</code> | <code>error</code>] (default: not set)
|
||||
</dt><dd>
|
||||
Lombok will flag any usage of <code>@SuperBuilder</code> as a warning or error if configured.
|
||||
</dd><dt>
|
||||
<code>lombok.singular.useGuava</code> = [<code>true</code> | <code>false</code>] (default: false)
|
||||
</dt><dd>
|
||||
If <code>true</code>, lombok will use guava's <code>ImmutableXxx</code> builders and types to implement <code>java.util</code> collection interfaces, instead of creating implementations based on <code>Collections.unmodifiableXxx</code>. You must ensure that guava is actually available on the classpath and buildpath if you use this setting. Guava is used automatically if your field/parameter has one of the guava <code>ImmutableXxx</code> types.
|
||||
</dd><dt>
|
||||
<code>lombok.singular.auto</code> = [<code>true</code> | <code>false</code>] (default: true)
|
||||
</dt><dd>
|
||||
If <code>true</code> (which is the default), lombok automatically tries to singularize your identifier name by assuming that it is a common english plural. If <code>false</code>, you must always explicitly specify the singular name, and lombok will generate an error if you don't (useful if you write your code in a language other than english).
|
||||
</dd>
|
||||
</@f.confKeys>
|
||||
|
||||
<@f.smallPrint>
|
||||
<p>
|
||||
@Singular support for <code>java.util.NavigableMap/Set</code> only works if you are compiling with JDK1.8 or higher.
|
||||
</p><p>
|
||||
The sorted collections (java.util: <code>SortedSet</code>, <code>NavigableSet</code>, <code>SortedMap</code>, <code>NavigableMap</code> and guava: <code>ImmutableSortedSet</code>, <code>ImmutableSortedMap</code>) require that the type argument of the collection has natural order (implements <code>java.util.Comparable</code>). There is no way to pass an explicit <code>Comparator</code> to use in the builder.
|
||||
</p><p>
|
||||
An <code>ArrayList</code> is used to store added elements as call methods of a <code>@Singular</code> marked field, if the target collection is from the <code>java.util</code> package, <em>even if the collection is a set or map</em>. Because lombok ensures that generated collections are compacted, a new backing instance of a set or map must be constructed anyway, and storing the data as an <code>ArrayList</code> during the build process is more efficient that storing it as a map or set. This behaviour is not externally visible, an implementation detail of the current implementation of the <code>java.util</code> recipes for <code>@Singular</code>.
|
||||
</p><p>
|
||||
The generated builder code heavily relies on generics to avoid class casting when using the builder.
|
||||
</p>
|
||||
</@f.smallPrint>
|
||||
</@f.scaffold>
|
||||
@@ -62,10 +62,14 @@
|
||||
<@main.feature title="@Helper" href="Helper">
|
||||
With a little help from my friends... Helper methods for java.
|
||||
</@main.feature>
|
||||
|
||||
|
||||
<@main.feature title="@FieldNameConstants" href="FieldNameConstants">
|
||||
Name... that... field! String constants for your field's names.
|
||||
</@main.feature>
|
||||
|
||||
<@main.feature title="@SuperBuilder" href="SuperBuilder">
|
||||
Bob now knows his ancestors: Builders with fields from superclasses, too.
|
||||
</@main.feature>
|
||||
</div>
|
||||
|
||||
<@f.confKeys>
|
||||
|
||||
Reference in new issue
Block a user