use of lombok.core.handlers.InclusionExclusionUtils.Included 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.core.handlers.InclusionExclusionUtils.Included in project lombok by rzwitserloot.
the class HandleSuperBuilder method handle.
@Override
public void handle(AnnotationValues<SuperBuilder> annotation, Annotation ast, EclipseNode annotationNode) {
handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.SUPERBUILDER_FLAG_USAGE, "@SuperBuilder");
SuperBuilderJob job = new SuperBuilderJob();
job.sourceNode = annotationNode;
job.source = ast;
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;
EclipseNode parent = annotationNode.up();
job.builderFields = new ArrayList<BuilderFieldData>();
TypeReference buildMethodReturnType;
boolean addCleaning = false;
List<EclipseNode> nonFinalNonDefaultedFields = null;
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;
TypeDeclaration td = (TypeDeclaration) parent.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, parent) || hasAnnotation("lombok.experimental.Value", parent));
for (EclipseNode fieldNode : HandleConstructor.findAllFields(parent, 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));
Annotation[] copyableAnnotations = findCopyableAnnotations(fieldNode);
BuilderFieldData bfd = new BuilderFieldData();
bfd.rawName = fieldNode.getName().toCharArray();
bfd.name = removePrefixFromField(fieldNode);
bfd.builderFieldName = bfd.name;
bfd.annotations = copyAnnotations(fd, copyableAnnotations);
bfd.type = fd.type;
bfd.singularData = getSingularData(fieldNode, ast, annInstance.setterPrefix());
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;
if (nonFinalNonDefaultedFields == null)
nonFinalNonDefaultedFields = new ArrayList<EclipseNode>();
nonFinalNonDefaultedFields.add(fieldNode);
}
if (isDefault != null) {
bfd.nameOfDefaultProvider = prefixWith(DEFAULT_PREFIX, bfd.name);
bfd.nameOfSetFlag = prefixWith(bfd.name, SET_PREFIX);
bfd.builderFieldName = prefixWith(bfd.name, VALUE_PREFIX);
MethodDeclaration md = HandleBuilder.generateDefaultProvider(bfd.nameOfDefaultProvider, td.typeParameters, fieldNode, ast);
if (md != null)
injectMethod(parent, md);
}
addObtainVia(bfd, fieldNode);
job.builderFields.add(bfd);
allFields.add(fieldNode);
}
job.typeParams = td.typeParameters != null ? td.typeParameters : new TypeParameter[0];
buildMethodReturnType = job.createBuilderParentTypeReference();
// <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.Set<String> usedNames = gatherUsedTypeNames(job.typeParams, td);
classGenericName = generateNonclashingNameFor(classGenericName, usedNames);
builderGenericName = generateNonclashingNameFor(builderGenericName, usedNames);
TypeParameter[] paddedTypeParameters;
{
paddedTypeParameters = new TypeParameter[job.typeParams.length + 2];
System.arraycopy(job.typeParams, 0, paddedTypeParameters, 0, job.typeParams.length);
TypeParameter c = new TypeParameter();
c.name = classGenericName.toCharArray();
c.type = cloneSelfType(job.parentType, job.source);
paddedTypeParameters[paddedTypeParameters.length - 2] = c;
TypeParameter b = new TypeParameter();
b.name = builderGenericName.toCharArray();
b.type = cloneSelfType(job.parentType, job.source);
paddedTypeParameters[paddedTypeParameters.length - 1] = b;
}
job.builderTypeParams = job.builderTypeParams_ = paddedTypeParameters;
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;
char[] superclassClassName = qualifiedTypeReference.getLastToken();
String builderClassNameTemplate = BuilderJob.getBuilderClassNameTemplate(annotationNode, null);
String superclassBuilderClassName = job.replaceBuilderClassName(superclassClassName, builderClassNameTemplate);
char[][] tokens = Arrays.copyOf(qualifiedTypeReference.tokens, qualifiedTypeReference.tokens.length + 1);
tokens[tokens.length - 1] = superclassBuilderClassName.toCharArray();
long[] poss = new long[tokens.length];
Arrays.fill(poss, job.getPos());
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) {
char[] superclassClassName = extendsClause.getTypeName()[0];
String builderClassNameTemplate = BuilderJob.getBuilderClassNameTemplate(annotationNode, null);
String superclassBuilderClassName = job.replaceBuilderClassName(superclassClassName, builderClassNameTemplate);
char[][] tokens = new char[][] { superclassClassName, superclassBuilderClassName.toCharArray() };
long[] poss = new long[tokens.length];
Arrays.fill(poss, job.getPos());
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);
}
job.builderAbstractClassName = job.builderClassName = job.replaceBuilderClassName(td.name);
job.builderAbstractClassNameArr = job.builderClassNameArr = job.builderAbstractClassName.toCharArray();
job.builderImplClassName = job.builderAbstractClassName + "Impl";
job.builderImplClassNameArr = job.builderImplClassName.toCharArray();
if (!constructorExists(parent, job.builderClassName)) {
generateBuilderBasedConstructor(job, superclassBuilderClass != null);
}
// Create the abstract builder class, or reuse an existing one.
job.builderAbstractType = findInnerClass(parent, job.builderClassName);
if (job.builderAbstractType == null) {
job.builderAbstractType = generateBuilderAbstractClass(job, superclassBuilderClass, classGenericName, builderGenericName);
} else {
TypeDeclaration builderTypeDeclaration = (TypeDeclaration) job.builderAbstractType.get();
if ((builderTypeDeclaration.modifiers & (ClassFileConstants.AccStatic | ClassFileConstants.AccAbstract)) == 0) {
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;
EclipseSingularizer singularizer = sd.getSingularizer();
if (singularizer == null)
continue;
if (singularizer.checkForAlreadyExistingNodesAndGenerateError(job.builderAbstractType, sd)) {
bfd.singularData = null;
}
}
}
// 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;
}
}
}
// Generate the fields in the abstract builder class that hold the values for the instance.
job.setBuilderToAbstract();
generateBuilderFields(job);
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(job.builderType, cleanDecl);
}
if (job.toBuilder) {
// Generate $fillValuesFrom() method in the abstract builder.
injectMethod(job.builderType, generateFillValuesMethod(job, superclassBuilderClass != null, builderGenericName, classGenericName));
// Generate $fillValuesFromInstanceIntoBuilder() method in the builder implementation class.
injectMethod(job.builderType, generateStaticFillValuesMethod(job, annInstance.setterPrefix()));
}
// Generate abstract self() and build() methods in the abstract builder.
injectMethod(job.builderType, generateAbstractSelfMethod(job, superclassBuilderClass != null, builderGenericName));
job.setBuilderToAbstract();
injectMethod(job.builderType, generateAbstractBuildMethod(job, superclassBuilderClass != null, classGenericName));
// 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.
if (methodExists("toString", job.builderType, 0) == MemberExistsResult.NOT_EXISTS) {
List<Included<EclipseNode, ToString.Include>> fieldNodes = new ArrayList<Included<EclipseNode, ToString.Include>>();
for (BuilderFieldData bfd : job.builderFields) {
for (EclipseNode f : bfd.createdFields) {
fieldNodes.add(new Included<EclipseNode, 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.
MethodDeclaration md = HandleToString.createToString(job.builderType, fieldNodes, true, superclassBuilderClass != null, ast, FieldAccess.ALWAYS_FIELD);
if (md != null) {
injectMethod(job.builderType, md);
}
}
if (addCleaning) {
job.setBuilderToAbstract();
injectMethod(job.builderType, generateCleanMethod(job));
}
boolean isAbstract = (td.modifiers & ClassFileConstants.AccAbstract) != 0;
if (isAbstract) {
// Only non-abstract classes get the Builder implementation.
return;
}
// Create the builder implementation class, or reuse an existing one.
job.builderImplType = findInnerClass(parent, job.builderImplClassName);
if (job.builderImplType == null) {
job.builderImplType = generateBuilderImplClass(job, job.builderImplClassName);
} else {
TypeDeclaration builderImplTypeDeclaration = (TypeDeclaration) job.builderImplType.get();
if ((builderImplTypeDeclaration.modifiers & ClassFileConstants.AccAbstract) != 0 || (builderImplTypeDeclaration.modifiers & ClassFileConstants.AccStatic) == 0) {
annotationNode.addError("Existing BuilderImpl must be a non-abstract static inner class.");
return;
}
sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(job.builderImplType, annotationNode);
}
job.setBuilderToImpl();
if (job.toBuilder) {
// Add the toBuilder() method to the annotated class.
switch(methodExists(TO_BUILDER_METHOD_NAME_STRING, job.parentType, 0)) {
case EXISTS_BY_USER:
break;
case NOT_EXISTS:
injectMethod(parent, generateToBuilderMethod(job));
break;
default:
}
}
// Create the self() and build() methods in the BuilderImpl.
job.setBuilderToImpl();
injectMethod(job.builderImplType, generateSelfMethod(job));
if (methodExists(job.buildMethodName, job.builderImplType, -1) == MemberExistsResult.NOT_EXISTS) {
job.setBuilderToImpl();
injectMethod(job.builderImplType, generateBuildMethod(job, buildMethodReturnType));
}
// Add the builder() method to the annotated class.
if (generateBuilderMethod && methodExists(job.builderMethodName, parent, -1) != MemberExistsResult.NOT_EXISTS)
generateBuilderMethod = false;
if (generateBuilderMethod) {
MethodDeclaration md = generateBuilderMethod(job);
if (md != null)
injectMethod(parent, md);
}
if (nonFinalNonDefaultedFields != null && generateBuilderMethod) {
for (EclipseNode 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.core.handlers.InclusionExclusionUtils.Included in project lombok by rzwitserloot.
the class HandleToString method handle.
public void handle(AnnotationValues<ToString> annotation, Annotation ast, EclipseNode annotationNode) {
handleFlagUsage(annotationNode, ConfigurationKeys.TO_STRING_FLAG_USAGE, "@ToString");
ToString ann = annotation.getInstance();
boolean onlyExplicitlyIncluded = annotationNode.getAst().getBooleanAnnotationValue(annotation, "onlyExplicitlyIncluded", ConfigurationKeys.TO_STRING_ONLY_EXPLICITLY_INCLUDED);
List<Included<EclipseNode, ToString.Include>> members = InclusionExclusionUtils.handleToStringMarking(annotationNode.up(), onlyExplicitlyIncluded, annotation, annotationNode);
if (members == null)
return;
Boolean callSuper = ann.callSuper();
if (!annotation.isExplicit("callSuper"))
callSuper = null;
Boolean doNotUseGettersConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_DO_NOT_USE_GETTERS);
boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration;
FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER;
Boolean fieldNamesConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_INCLUDE_FIELD_NAMES);
boolean includeFieldNames = annotation.isExplicit("includeFieldNames") || fieldNamesConfiguration == null ? ann.includeFieldNames() : fieldNamesConfiguration;
generateToString(annotationNode.up(), annotationNode, members, includeFieldNames, callSuper, true, fieldAccess);
}
use of lombok.core.handlers.InclusionExclusionUtils.Included in project lombok by rzwitserloot.
the class HandleBuilder method handle.
@Override
public void handle(AnnotationValues<Builder> annotation, JCAnnotation ast, JavacNode annotationNode) {
final String BUILDER_NODE_NOT_SUPPORTED_ERR = "@Builder is only supported on classes, records, constructors, and methods.";
handleFlagUsage(annotationNode, ConfigurationKeys.BUILDER_FLAG_USAGE, "@Builder");
BuilderJob job = new BuilderJob();
job.sourceNode = annotationNode;
job.checkerFramework = getCheckerFrameworkVersion(annotationNode);
job.isStatic = true;
Builder annInstance = annotation.getInstance();
job.init(annotation, annInstance, annotationNode);
java.util.List<Name> typeArgsForToBuilder = null;
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 Builder annotation yet, we need it for @Jacksonized.
JavacNode parent = annotationNode.up();
job.builderFields = new ArrayList<BuilderFieldData>();
JCExpression buildMethodReturnType;
job.typeParams = List.nil();
List<JCExpression> buildMethodThrownExceptions;
Name nameOfBuilderMethod;
JavacNode fillParametersFrom = parent.get() instanceof JCMethodDecl ? parent : null;
boolean addCleaning = false;
ArrayList<JavacNode> nonFinalNonDefaultedFields = null;
if (!isStaticAllowed(upToTypeNode(parent))) {
annotationNode.addError("@Builder is not supported on non-static nested classes.");
return;
}
if (parent.get() instanceof JCClassDecl) {
if (!isClass(parent) && !isRecord(parent)) {
annotationNode.addError(BUILDER_NODE_NOT_SUPPORTED_ERR);
return;
}
job.parentType = parent;
JCClassDecl td = (JCClassDecl) parent.get();
ListBuffer<JavacNode> allFields = new ListBuffer<JavacNode>();
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 = generateDefaultProvider(bfd.nameOfDefaultProvider, fieldNode, td.typarams, job);
if (md != null)
injectMethod(parent, md);
}
addObtainVia(bfd, fieldNode);
job.builderFields.add(bfd);
allFields.append(fieldNode);
}
if (!isRecord(parent)) {
// Records ship with a canonical constructor that acts as @AllArgsConstructor - just use that one.
handleConstructor.generateConstructor(parent, AccessLevel.PACKAGE, List.<JCAnnotation>nil(), allFields.toList(), false, null, SkipIfConstructorExists.I_AM_BUILDER, annotationNode);
}
buildMethodReturnType = namePlusTypeParamsToTypeReference(parent.getTreeMaker(), parent, td.typarams);
job.typeParams = job.builderTypeParams = td.typarams;
buildMethodThrownExceptions = List.nil();
nameOfBuilderMethod = null;
job.builderClassName = job.replaceBuilderClassName(td.name);
if (!checkName("builderClassName", job.builderClassName, annotationNode))
return;
} else if (fillParametersFrom != null && fillParametersFrom.getName().toString().equals("<init>")) {
JCMethodDecl jmd = (JCMethodDecl) fillParametersFrom.get();
if (!jmd.typarams.isEmpty()) {
annotationNode.addError("@Builder is not supported on constructors with constructor type parameters.");
return;
}
job.parentType = parent.up();
JCClassDecl td = (JCClassDecl) job.parentType.get();
job.typeParams = job.builderTypeParams = td.typarams;
buildMethodReturnType = job.createBuilderParentTypeReference();
buildMethodThrownExceptions = jmd.thrown;
nameOfBuilderMethod = null;
job.builderClassName = job.replaceBuilderClassName(td.name);
if (!checkName("builderClassName", job.builderClassName, annotationNode))
return;
} else if (fillParametersFrom != null) {
job.parentType = parent.up();
JCClassDecl td = (JCClassDecl) job.parentType.get();
JCMethodDecl jmd = (JCMethodDecl) fillParametersFrom.get();
job.isStatic = (jmd.mods.flags & Flags.STATIC) != 0;
JCExpression fullReturnType = jmd.restype;
buildMethodReturnType = fullReturnType;
job.typeParams = job.builderTypeParams = jmd.typarams;
buildMethodThrownExceptions = jmd.thrown;
nameOfBuilderMethod = jmd.name;
if (buildMethodReturnType instanceof JCTypeApply) {
buildMethodReturnType = cloneType(job.getTreeMaker(), buildMethodReturnType, annotationNode);
}
if (job.builderClassName.indexOf('*') > -1) {
String replStr = returnTypeToBuilderClassName(annotationNode, td, buildMethodReturnType, job.typeParams);
// shuold not happen
if (replStr == null)
return;
job.builderClassName = job.builderClassName.replace("*", replStr);
}
if (job.toBuilder) {
if (fullReturnType instanceof JCArrayTypeTree) {
annotationNode.addError(TO_BUILDER_NOT_SUPPORTED);
return;
}
Name simpleName;
String pkg;
List<JCExpression> tpOnRet = List.nil();
if (fullReturnType instanceof JCTypeApply) {
tpOnRet = ((JCTypeApply) fullReturnType).arguments;
}
JCExpression namingType = fullReturnType;
if (buildMethodReturnType instanceof JCTypeApply)
namingType = ((JCTypeApply) buildMethodReturnType).clazz;
if (namingType instanceof JCIdent) {
simpleName = ((JCIdent) namingType).name;
pkg = null;
} else if (namingType instanceof JCFieldAccess) {
JCFieldAccess jcfa = (JCFieldAccess) namingType;
simpleName = jcfa.name;
pkg = unpack(jcfa.selected);
if (pkg.startsWith("ERR:")) {
String err = pkg.substring(4, pkg.indexOf("__ERR__"));
annotationNode.addError(err);
return;
}
} else {
annotationNode.addError("Expected a (parameterized) type here instead of a " + namingType.getClass().getName());
return;
}
if (pkg != null && !parent.getPackageDeclaration().equals(pkg)) {
annotationNode.addError(TO_BUILDER_NOT_SUPPORTED);
return;
}
if (!job.parentType.getName().contentEquals(simpleName)) {
annotationNode.addError(TO_BUILDER_NOT_SUPPORTED);
return;
}
List<JCTypeParameter> tpOnMethod = jmd.typarams;
List<JCTypeParameter> tpOnType = ((JCClassDecl) job.parentType.get()).typarams;
typeArgsForToBuilder = new ArrayList<Name>();
for (JCTypeParameter tp : tpOnMethod) {
int pos = -1;
int idx = -1;
for (JCExpression tOnRet : tpOnRet) {
idx++;
if (!(tOnRet instanceof JCIdent))
continue;
if (((JCIdent) tOnRet).name != tp.name)
continue;
pos = idx;
}
if (pos == -1 || tpOnType.size() <= pos) {
annotationNode.addError("@Builder(toBuilder=true) requires that each type parameter on the static method is part of the typeargs of the return value. Type parameter " + tp.name + " is not part of the return type.");
return;
}
typeArgsForToBuilder.add(tpOnType.get(pos).name);
}
}
} else {
annotationNode.addError(BUILDER_NODE_NOT_SUPPORTED_ERR);
return;
}
if (fillParametersFrom != null) {
for (JavacNode param : fillParametersFrom.down()) {
if (param.getKind() != Kind.ARGUMENT)
continue;
BuilderFieldData bfd = new BuilderFieldData();
JCVariableDecl raw = (JCVariableDecl) param.get();
bfd.name = raw.name;
bfd.builderFieldName = bfd.name;
bfd.rawName = raw.name;
bfd.annotations = findCopyableAnnotations(param);
bfd.type = raw.vartype;
bfd.singularData = getSingularData(param, annInstance.setterPrefix());
bfd.originalFieldNode = param;
addObtainVia(bfd, param);
job.builderFields.add(bfd);
}
}
job.builderType = findInnerClass(job.parentType, job.builderClassName);
if (job.builderType == null) {
job.builderType = makeBuilderClass(job);
recursiveSetGeneratedBy(job.builderType.get(), annotationNode);
} else {
JCClassDecl builderTypeDeclaration = (JCClassDecl) job.builderType.get();
if (job.isStatic && !builderTypeDeclaration.getModifiers().getFlags().contains(Modifier.STATIC)) {
annotationNode.addError("Existing Builder must be a static inner class.");
return;
} else if (!job.isStatic && builderTypeDeclaration.getModifiers().getFlags().contains(Modifier.STATIC)) {
annotationNode.addError("Existing Builder must be a non-static inner class.");
return;
}
sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(job.builderType, 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.builderType, sd)) {
bfd.singularData = null;
}
}
}
}
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;
}
}
}
generateBuilderFields(job);
if (addCleaning) {
JavacTreeMaker maker = job.getTreeMaker();
JCVariableDecl uncleanField = maker.VarDef(maker.Modifiers(Flags.PRIVATE), job.builderType.toName(CLEAN_FIELD_NAME), maker.TypeIdent(CTC_BOOLEAN), null);
injectFieldAndMarkGenerated(job.builderType, uncleanField);
recursiveSetGeneratedBy(uncleanField, annotationNode);
}
if (constructorExists(job.builderType) == MemberExistsResult.NOT_EXISTS) {
JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PACKAGE, List.<JCAnnotation>nil(), job.builderType, List.<JavacNode>nil(), false, annotationNode);
if (cd != null)
injectMethod(job.builderType, cd);
}
for (BuilderFieldData bfd : job.builderFields) {
makePrefixedSetterMethodsForBuilder(job, bfd, annInstance.setterPrefix());
}
{
MemberExistsResult methodExists = methodExists(job.buildMethodName, job.builderType, -1);
if (methodExists == MemberExistsResult.EXISTS_BY_LOMBOK)
methodExists = methodExists(job.buildMethodName, job.builderType, 0);
if (methodExists == MemberExistsResult.NOT_EXISTS) {
JCMethodDecl md = generateBuildMethod(job, nameOfBuilderMethod, buildMethodReturnType, buildMethodThrownExceptions, addCleaning);
if (md != null) {
recursiveSetGeneratedBy(md, annotationNode);
injectMethod(job.builderType, md);
}
}
}
if (methodExists("toString", job.builderType, 0) == MemberExistsResult.NOT_EXISTS) {
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));
}
}
JCMethodDecl md = HandleToString.createToString(job.builderType, fieldNodes, true, false, FieldAccess.ALWAYS_FIELD, job.sourceNode);
if (md != null)
injectMethod(job.builderType, md);
}
if (addCleaning)
injectMethod(job.builderType, generateCleanMethod(job));
if (generateBuilderMethod && methodExists(job.builderMethodName, job.parentType, -1) != MemberExistsResult.NOT_EXISTS)
generateBuilderMethod = false;
if (generateBuilderMethod) {
JCMethodDecl md = generateBuilderMethod(job);
recursiveSetGeneratedBy(md, annotationNode);
if (md != null)
injectMethod(job.parentType, md);
}
if (job.toBuilder) {
switch(methodExists(TO_BUILDER_METHOD_NAME, job.parentType, 0)) {
case EXISTS_BY_USER:
annotationNode.addWarning("Not generating toBuilder() as it already exists.");
return;
case NOT_EXISTS:
List<JCTypeParameter> tps = job.typeParams;
if (typeArgsForToBuilder != null) {
ListBuffer<JCTypeParameter> lb = new ListBuffer<JCTypeParameter>();
JavacTreeMaker maker = job.getTreeMaker();
for (Name n : typeArgsForToBuilder) {
lb.append(maker.TypeParameter(n, List.<JCExpression>nil()));
}
tps = lb.toList();
}
JCMethodDecl md = generateToBuilderMethod(job, tps, annInstance.setterPrefix());
if (md != null) {
recursiveSetGeneratedBy(md, annotationNode);
injectMethod(job.parentType, md);
}
}
}
if (nonFinalNonDefaultedFields != null && generateBuilderMethod) {
for (JavacNode fieldNode : nonFinalNonDefaultedFields) {
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.");
}
}
}
use of lombok.core.handlers.InclusionExclusionUtils.Included in project lombok by rzwitserloot.
the class HandleEqualsAndHashCode method generateEqualsAndHashCodeForType.
public void generateEqualsAndHashCodeForType(JavacNode typeNode, JavacNode source) {
if (hasAnnotation(EqualsAndHashCode.class, typeNode)) {
// The annotation will make it happen, so we can skip it.
return;
}
Boolean doNotUseGettersConfiguration = typeNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS);
FieldAccess access = doNotUseGettersConfiguration == null || !doNotUseGettersConfiguration ? FieldAccess.GETTER : FieldAccess.PREFER_FIELD;
java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members = InclusionExclusionUtils.handleEqualsAndHashCodeMarking(typeNode, null, null);
generateMethods(typeNode, source, members, null, false, false, access, List.<JCAnnotation>nil());
}
Aggregations