use of lombok.javac.handlers.HandleBuilder.BuilderFieldData in project lombok by rzwitserloot.
the class HandleSuperBuilder method generateCleanMethod.
private JCMethodDecl generateCleanMethod(java.util.List<BuilderFieldData> builderFields, JavacNode type, JavacNode 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);
}
use of lombok.javac.handlers.HandleBuilder.BuilderFieldData in project lombok by rzwitserloot.
the class HandleSuperBuilder method generateStaticFillValuesMethod.
/**
* Generates a <code>$fillValuesFromInstanceIntoBuilder()</code> method in
* the builder implementation class that copies all fields from the instance
* to the builder. It looks like this:
*
* <pre>
* protected B $fillValuesFromInstanceIntoBuilder(Foobar instance, FoobarBuilder<?, ?> b) {
* b.field(instance.field);
* }
* </pre>
*/
private JCMethodDecl generateStaticFillValuesMethod(SuperBuilderJob job, String setterPrefix) {
JavacTreeMaker maker = job.getTreeMaker();
List<JCAnnotation> annotations = List.nil();
JCModifiers modifiers = maker.Modifiers(Flags.PRIVATE | Flags.STATIC, annotations);
Name name = job.toName(STATIC_FILL_VALUES_METHOD_NAME);
JCExpression returnType = maker.TypeIdent(CTC_VOID);
// 1st parameter: "Foobar instance"
JCVariableDecl paramInstance = maker.VarDef(maker.Modifiers(Flags.PARAMETER | Flags.FINAL), job.toName(INSTANCE_VARIABLE_NAME), cloneSelfType(job.parentType), null);
// 2nd parameter: "FoobarBuilder<?, ?> b" (plus generics on the annotated type)
// First add all generics that are present on the parent type.
ListBuffer<JCExpression> typeParamsForBuilderParameter = getTypeParamExpressions(job.typeParams, maker, job.sourceNode);
// Now add the <?, ?>.
JCWildcard wildcard = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null);
typeParamsForBuilderParameter.append(wildcard);
wildcard = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null);
typeParamsForBuilderParameter.append(wildcard);
JCTypeApply builderType = maker.TypeApply(namePlusTypeParamsToTypeReference(maker, job.parentType, job.getBuilderClassName(), false, List.<JCTypeParameter>nil()), typeParamsForBuilderParameter.toList());
JCVariableDecl paramBuilder = maker.VarDef(maker.Modifiers(Flags.PARAMETER | Flags.FINAL), job.toName(BUILDER_VARIABLE_NAME), builderType, null);
ListBuffer<JCStatement> body = new ListBuffer<JCStatement>();
// Call the builder's setter methods to fill the values from the instance.
for (BuilderFieldData bfd : job.builderFields) {
JCExpressionStatement exec = createSetterCallWithInstanceValue(bfd, job, setterPrefix);
body.append(exec);
}
JCBlock bodyBlock = maker.Block(0, body.toList());
return maker.MethodDef(modifiers, name, returnType, copyTypeParams(job.builderType, job.typeParams), List.of(paramInstance, paramBuilder), List.<JCExpression>nil(), bodyBlock, null);
}
use of lombok.javac.handlers.HandleBuilder.BuilderFieldData in project lombok by rzwitserloot.
the class HandleSuperBuilder method handle.
@Override
public void handle(AnnotationValues<SuperBuilder> annotation, JCAnnotation ast, JavacNode annotationNode) {
handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.SUPERBUILDER_FLAG_USAGE, "@SuperBuilder");
SuperBuilderJob job = new SuperBuilderJob();
job.sourceNode = annotationNode;
job.checkerFramework = getCheckerFrameworkVersion(annotationNode);
job.isStatic = true;
SuperBuilder annInstance = annotation.getInstance();
job.init(annotation, annInstance, annotationNode);
boolean generateBuilderMethod;
if (job.builderMethodName.isEmpty()) {
generateBuilderMethod = false;
} else if (!checkName("builderMethodName", job.builderMethodName, annotationNode)) {
return;
} else {
generateBuilderMethod = true;
}
if (!checkName("buildMethodName", job.buildMethodName, annotationNode))
return;
// Do not delete the SuperBuilder annotation here, we need it for @Jacksonized.
JavacNode parent = annotationNode.up();
job.builderFields = new ArrayList<BuilderFieldData>();
job.typeParams = List.nil();
List<JCExpression> buildMethodThrownExceptions = List.nil();
List<JCExpression> superclassTypeParams = List.nil();
boolean addCleaning = false;
if (!isClass(parent)) {
annotationNode.addError("@SuperBuilder is only supported on classes.");
return;
}
if (!isStaticAllowed(parent)) {
annotationNode.addError("@SuperBuilder is not supported on non-static nested classes.");
return;
}
job.parentType = parent;
JCClassDecl td = (JCClassDecl) parent.get();
// Gather all fields of the class that should be set by the builder.
ArrayList<JavacNode> nonFinalNonDefaultedFields = null;
boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation("lombok.experimental.Value", parent));
for (JavacNode fieldNode : HandleConstructor.findAllFields(parent, true)) {
JCVariableDecl fd = (JCVariableDecl) fieldNode.get();
JavacNode isDefault = findAnnotation(Builder.Default.class, fieldNode, false);
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.builderFieldName = bfd.name;
bfd.annotations = findCopyableAnnotations(fieldNode);
bfd.type = fd.vartype;
bfd.singularData = getSingularData(fieldNode, annInstance.setterPrefix());
bfd.originalFieldNode = fieldNode;
if (bfd.singularData != null && isDefault != null) {
isDefault.addError("@Builder.Default and @Singular cannot be mixed.");
findAnnotation(Builder.Default.class, fieldNode, true);
isDefault = null;
}
if (fd.init == null && isDefault != null) {
isDefault.addWarning("@Builder.Default requires an initializing expression (' = something;').");
findAnnotation(Builder.Default.class, fieldNode, true);
isDefault = null;
}
if (fd.init != null && isDefault == null) {
if (isFinal)
continue;
if (nonFinalNonDefaultedFields == null)
nonFinalNonDefaultedFields = new ArrayList<JavacNode>();
nonFinalNonDefaultedFields.add(fieldNode);
}
if (isDefault != null) {
bfd.nameOfDefaultProvider = parent.toName(DEFAULT_PREFIX + bfd.name);
bfd.nameOfSetFlag = parent.toName(bfd.name + SET_PREFIX);
bfd.builderFieldName = parent.toName(bfd.name + VALUE_PREFIX);
JCMethodDecl md = HandleBuilder.generateDefaultProvider(bfd.nameOfDefaultProvider, fieldNode, td.typarams, job);
if (md != null)
injectMethod(parent, md);
}
addObtainVia(bfd, fieldNode);
job.builderFields.add(bfd);
}
job.typeParams = job.builderTypeParams = td.typarams;
job.builderClassName = job.replaceBuilderClassName(td.name);
if (!checkName("builderClassName", job.builderClassName, annotationNode))
return;
// <C, B> are the generics for our builder.
String classGenericName = "C";
String builderGenericName = "B";
// We have to make sure that the generics' names do not collide with any generics on the annotated class,
// the classname itself, or any member type name of the annotated class.
// For instance, if there are generics <B, B2, C> on the annotated class, use "C2" and "B3" for our builder.
java.util.HashSet<String> usedNames = gatherUsedTypeNames(job.typeParams, td);
classGenericName = generateNonclashingNameFor(classGenericName, usedNames);
builderGenericName = generateNonclashingNameFor(builderGenericName, usedNames);
JavacTreeMaker maker = annotationNode.getTreeMaker();
{
JCExpression annotatedClass = namePlusTypeParamsToTypeReference(maker, parent, job.typeParams);
JCTypeParameter c = maker.TypeParameter(parent.toName(classGenericName), List.<JCExpression>of(annotatedClass));
ListBuffer<JCExpression> typeParamsForBuilder = getTypeParamExpressions(job.typeParams, maker, job.sourceNode);
typeParamsForBuilder.append(maker.Ident(parent.toName(classGenericName)));
typeParamsForBuilder.append(maker.Ident(parent.toName(builderGenericName)));
JCTypeApply typeApply = maker.TypeApply(namePlusTypeParamsToTypeReference(maker, parent, job.getBuilderClassName(), false, List.<JCTypeParameter>nil()), typeParamsForBuilder.toList());
JCTypeParameter d = maker.TypeParameter(parent.toName(builderGenericName), List.<JCExpression>of(typeApply));
if (job.typeParams == null || job.typeParams.isEmpty()) {
job.builderTypeParams_ = List.of(c, d);
} else {
job.builderTypeParams_ = job.typeParams.append(c).append(d);
}
}
JCTree extendsClause = Javac.getExtendsClause(td);
JCExpression superclassBuilderClass = 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 superclassName = ((JCFieldAccess) extendsClause).getIdentifier();
String builderClassNameTemplate = BuilderJob.getBuilderClassNameTemplate(annotationNode, null);
String superclassBuilderClassName = job.replaceBuilderClassName(superclassName.toString(), builderClassNameTemplate);
superclassBuilderClass = parent.getTreeMaker().Select((JCFieldAccess) extendsClause, parent.toName(superclassBuilderClassName));
} else if (extendsClause != null) {
String builderClassNameTemplate = BuilderJob.getBuilderClassNameTemplate(annotationNode, null);
String superclassBuilderClassName = job.replaceBuilderClassName(extendsClause.toString(), builderClassNameTemplate);
superclassBuilderClass = chainDots(parent, extendsClause.toString(), superclassBuilderClassName);
}
// Check validity of @ObtainVia fields, and add check if adding cleaning for @Singular is necessary.
for (BuilderFieldData bfd : job.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;
}
}
}
job.builderAbstractClassName = job.builderClassName = job.replaceBuilderClassName(td.name);
job.builderImplClassName = job.builderAbstractClassName + "Impl";
// Create the abstract builder class.
job.builderAbstractType = findInnerClass(parent, job.builderClassName);
if (job.builderAbstractType == null) {
job.builderAbstractType = generateBuilderAbstractClass(job, superclassBuilderClass, superclassTypeParams, classGenericName, builderGenericName);
recursiveSetGeneratedBy(job.builderAbstractType.get(), annotationNode);
} else {
JCClassDecl builderTypeDeclaration = (JCClassDecl) job.builderAbstractType.get();
if (!builderTypeDeclaration.getModifiers().getFlags().contains(Modifier.STATIC) || !builderTypeDeclaration.getModifiers().getFlags().contains(Modifier.ABSTRACT)) {
annotationNode.addError("Existing Builder must be an abstract static inner class.");
return;
}
sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(job.builderAbstractType, annotationNode);
// Generate errors for @Singular BFDs that have one already defined node.
for (BuilderFieldData bfd : job.builderFields) {
SingularData sd = bfd.singularData;
if (sd == null)
continue;
JavacSingularizer singularizer = sd.getSingularizer();
if (singularizer == null)
continue;
if (singularizer.checkForAlreadyExistingNodesAndGenerateError(job.builderAbstractType, sd)) {
bfd.singularData = null;
}
}
}
// Generate the fields in the abstract builder class that hold the values for the instance.
job.setBuilderToAbstract();
generateBuilderFields(job.builderType, job.builderFields, annotationNode);
if (addCleaning) {
JCVariableDecl uncleanField = maker.VarDef(maker.Modifiers(Flags.PRIVATE), job.toName("$lombokUnclean"), maker.TypeIdent(CTC_BOOLEAN), null);
recursiveSetGeneratedBy(uncleanField, annotationNode);
injectFieldAndMarkGenerated(job.builderType, uncleanField);
}
if (job.toBuilder) {
// Generate $fillValuesFrom() method in the abstract builder.
JCMethodDecl fvm = generateFillValuesMethod(job, superclassBuilderClass != null, builderGenericName, classGenericName);
recursiveSetGeneratedBy(fvm, annotationNode);
injectMethod(job.builderType, fvm);
// Generate $fillValuesFromInstanceIntoBuilder() method in the builder implementation class.
JCMethodDecl sfvm = generateStaticFillValuesMethod(job, annInstance.setterPrefix());
recursiveSetGeneratedBy(sfvm, annotationNode);
injectMethod(job.builderType, sfvm);
}
// Generate abstract self() and build() methods in the abstract builder.
JCMethodDecl asm = generateAbstractSelfMethod(job, superclassBuilderClass != null, builderGenericName);
recursiveSetGeneratedBy(asm, annotationNode);
injectMethod(job.builderType, asm);
JCMethodDecl abm = generateAbstractBuildMethod(job, superclassBuilderClass != null, classGenericName);
recursiveSetGeneratedBy(abm, annotationNode);
injectMethod(job.builderType, abm);
// Create the setter methods in the abstract builder.
for (BuilderFieldData bfd : job.builderFields) {
generateSetterMethodsForBuilder(job, bfd, builderGenericName, annInstance.setterPrefix());
}
// 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 : job.builderFields) {
for (JavacNode f : bfd.createdFields) {
fieldNodes.add(new Included<JavacNode, ToString.Include>(f, null, true, false));
}
}
// Let toString() call super.toString() if there is a superclass, so that it also shows fields from the superclass' builder.
JCMethodDecl toStringMethod = HandleToString.createToString(job.builderType, fieldNodes, true, superclassBuilderClass != null, FieldAccess.ALWAYS_FIELD, annotationNode);
if (toStringMethod != null)
injectMethod(job.builderType, toStringMethod);
// If clean methods are requested, add them now.
if (addCleaning) {
JCMethodDecl md = generateCleanMethod(job.builderFields, job.builderType, annotationNode);
recursiveSetGeneratedBy(md, annotationNode);
injectMethod(job.builderType, md);
}
boolean isAbstract = (td.mods.flags & Flags.ABSTRACT) != 0;
if (!isAbstract) {
// Only non-abstract classes get the Builder implementation.
// Create the builder implementation class.
job.builderImplType = findInnerClass(parent, job.builderImplClassName);
if (job.builderImplType == null) {
job.builderImplType = generateBuilderImplClass(job);
recursiveSetGeneratedBy(job.builderImplType.get(), annotationNode);
} else {
JCClassDecl builderImplTypeDeclaration = (JCClassDecl) job.builderImplType.get();
if (!builderImplTypeDeclaration.getModifiers().getFlags().contains(Modifier.STATIC) || builderImplTypeDeclaration.getModifiers().getFlags().contains(Modifier.ABSTRACT)) {
annotationNode.addError("Existing BuilderImpl must be a non-abstract static inner class.");
return;
}
sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(job.builderImplType, annotationNode);
}
// Create a simple constructor for the BuilderImpl class.
JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PRIVATE, List.<JCAnnotation>nil(), job.builderImplType, List.<JavacNode>nil(), false, annotationNode);
if (cd != null)
injectMethod(job.builderImplType, cd);
job.setBuilderToImpl();
// Create the self() and build() methods in the BuilderImpl.
JCMethodDecl selfMethod = generateSelfMethod(job);
recursiveSetGeneratedBy(selfMethod, annotationNode);
injectMethod(job.builderType, selfMethod);
if (methodExists(job.buildMethodName, job.builderType, -1) == MemberExistsResult.NOT_EXISTS) {
JCMethodDecl buildMethod = generateBuildMethod(job, buildMethodThrownExceptions);
recursiveSetGeneratedBy(buildMethod, annotationNode);
injectMethod(job.builderType, buildMethod);
}
}
// Generate a constructor in the annotated class that takes a builder as argument.
if (!constructorExists(job.parentType, job.builderAbstractClassName)) {
job.setBuilderToAbstract();
generateBuilderBasedConstructor(job, superclassBuilderClass != null);
}
if (!isAbstract) {
// Allow users to specify their own builder() methods, e.g., to provide default values.
if (generateBuilderMethod && methodExists(job.builderMethodName, job.parentType, -1) != MemberExistsResult.NOT_EXISTS)
generateBuilderMethod = false;
if (generateBuilderMethod) {
JCMethodDecl builderMethod = generateBuilderMethod(job);
if (builderMethod != null) {
recursiveSetGeneratedBy(builderMethod, annotationNode);
injectMethod(job.parentType, builderMethod);
}
}
// Add the toBuilder() method to the annotated class.
if (job.toBuilder) {
switch(methodExists(TO_BUILDER_METHOD_NAME, job.parentType, 0)) {
case EXISTS_BY_USER:
break;
case NOT_EXISTS:
JCMethodDecl md = generateToBuilderMethod(job);
if (md != null) {
recursiveSetGeneratedBy(md, annotationNode);
injectMethod(job.parentType, md);
}
break;
default:
}
}
}
if (nonFinalNonDefaultedFields != null && generateBuilderMethod) {
for (JavacNode fieldNode : nonFinalNonDefaultedFields) {
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.");
}
}
}
use of lombok.javac.handlers.HandleBuilder.BuilderFieldData in project lombok by rzwitserloot.
the class HandleSuperBuilder method generateBuilderFields.
private void generateBuilderFields(JavacNode builderType, java.util.List<BuilderFieldData> builderFields, JavacNode 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);
}
java.util.List<JCVariableDecl> generated = new ArrayList<JCVariableDecl>();
for (int i = len - 1; i >= 0; i--) {
BuilderFieldData bfd = builderFields.get(i);
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
java.util.List<JavacNode> fields = bfd.singularData.getSingularizer().generateFields(bfd.singularData, builderType, source);
for (JavacNode field : fields) {
generated.add((JCVariableDecl) field.get());
}
bfd.createdFields.addAll(fields);
} else {
JavacNode field = null, setFlag = null;
for (JavacNode exists : existing) {
Name n = ((JCVariableDecl) exists.get()).name;
if (n.equals(bfd.builderFieldName))
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.builderFieldName, cloneType(maker, bfd.type, source), null);
field = injectFieldAndMarkGenerated(builderType, newField);
generated.add(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);
generated.add(newField);
}
bfd.createdFields.add(field);
}
}
for (JCVariableDecl gen : generated) recursiveSetGeneratedBy(gen, source);
}
use of lombok.javac.handlers.HandleBuilder.BuilderFieldData in project lombok by rzwitserloot.
the class HandleSuperBuilder method generateBuilderBasedConstructor.
/**
* 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 callBuilderBasedSuperConstructor
* If {@code true}, the constructor will explicitly call a super
* constructor with the builder as argument. Requires
* {@code builderClassAsParameter != null}.
*/
private void generateBuilderBasedConstructor(SuperBuilderJob job, boolean callBuilderBasedSuperConstructor) {
JavacTreeMaker maker = job.getTreeMaker();
AccessLevel level = AccessLevel.PROTECTED;
ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();
Name builderVariableName = job.toName(BUILDER_VARIABLE_NAME);
for (BuilderFieldData bfd : job.builderFields) {
JCExpression rhs;
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
bfd.singularData.getSingularizer().appendBuildCode(bfd.singularData, bfd.originalFieldNode, job.sourceNode, statements, bfd.builderFieldName, "b");
rhs = maker.Ident(bfd.singularData.getPluralName());
} else {
rhs = maker.Select(maker.Ident(builderVariableName), bfd.builderFieldName);
}
JCFieldAccess fieldInThis = maker.Select(maker.Ident(job.toName("this")), bfd.rawName);
JCStatement assign = maker.Exec(maker.Assign(fieldInThis, rhs));
// In case of @Builder.Default, set the value to the default if it was not set in the builder.
if (bfd.nameOfSetFlag != null) {
JCFieldAccess setField = maker.Select(maker.Ident(builderVariableName), bfd.nameOfSetFlag);
fieldInThis = maker.Select(maker.Ident(job.toName("this")), bfd.rawName);
JCExpression parentTypeRef = namePlusTypeParamsToTypeReference(maker, job.parentType, List.<JCTypeParameter>nil());
JCAssign assignDefault = maker.Assign(fieldInThis, maker.Apply(typeParameterNames(maker, ((JCClassDecl) job.parentType.get()).typarams), maker.Select(parentTypeRef, bfd.nameOfDefaultProvider), List.<JCExpression>nil()));
statements.append(maker.If(setField, assign, maker.Exec(assignDefault)));
} else {
statements.append(assign);
}
if (hasNonNullAnnotations(bfd.originalFieldNode)) {
JCStatement nullCheck = generateNullCheck(maker, bfd.originalFieldNode, job.sourceNode);
if (nullCheck != null)
statements.append(nullCheck);
}
}
List<JCAnnotation> annsOnMethod = job.checkerFramework.generateSideEffectFree() ? List.of(maker.Annotation(genTypeRef(job.parentType, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil())) : List.<JCAnnotation>nil();
JCModifiers mods = maker.Modifiers(toJavacModifier(level), annsOnMethod);
// Create a constructor that has just the builder as parameter.
ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, job.getContext());
// First add all generics that are present on the parent type.
ListBuffer<JCExpression> typeParamsForBuilderParameter = getTypeParamExpressions(job.typeParams, maker, job.sourceNode);
// Now add the <?, ?>.
JCWildcard wildcard = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null);
typeParamsForBuilderParameter.append(wildcard);
wildcard = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null);
typeParamsForBuilderParameter.append(wildcard);
JCTypeApply paramType = maker.TypeApply(namePlusTypeParamsToTypeReference(maker, job.parentType, job.getBuilderClassName(), false, List.<JCTypeParameter>nil()), 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(job.toName("super")), List.<JCExpression>of(maker.Ident(builderVariableName)));
statements.prepend(maker.Exec(callToSuperConstructor));
}
JCMethodDecl constr = recursiveSetGeneratedBy(maker.MethodDef(mods, job.toName("<init>"), null, List.<JCTypeParameter>nil(), params.toList(), List.<JCExpression>nil(), maker.Block(0L, statements.toList()), null), job.sourceNode);
injectMethod(job.parentType, constr);
}
Aggregations