Search in sources :

Example 1 with Included

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.");
        }
    }
}
Also used : BuilderFieldData(lombok.javac.handlers.HandleBuilder.BuilderFieldData) SuperBuilder(lombok.experimental.SuperBuilder) JCFieldAccess(com.sun.tools.javac.tree.JCTree.JCFieldAccess) HandleBuilder(lombok.javac.handlers.HandleBuilder) Builder(lombok.Builder) SuperBuilder(lombok.experimental.SuperBuilder) ListBuffer(com.sun.tools.javac.util.ListBuffer) ArrayList(java.util.ArrayList) JCTypeApply(com.sun.tools.javac.tree.JCTree.JCTypeApply) JavacSingularizer(lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer) ToString(lombok.ToString) Name(com.sun.tools.javac.util.Name) JavacNode(lombok.javac.JavacNode) JCClassDecl(com.sun.tools.javac.tree.JCTree.JCClassDecl) JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) JavacTreeMaker(lombok.javac.JavacTreeMaker) Included(lombok.core.handlers.InclusionExclusionUtils.Included) JCTree(com.sun.tools.javac.tree.JCTree) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl) JCTypeParameter(com.sun.tools.javac.tree.JCTree.JCTypeParameter) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) SingularData(lombok.javac.handlers.JavacSingularsRecipes.SingularData) ToString(lombok.ToString)

Example 2 with Included

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.");
        }
    }
}
Also used : BuilderFieldData(lombok.eclipse.handlers.HandleBuilder.BuilderFieldData) SuperBuilder(lombok.experimental.SuperBuilder) TypeParameter(org.eclipse.jdt.internal.compiler.ast.TypeParameter) Builder(lombok.Builder) SuperBuilder(lombok.experimental.SuperBuilder) HandleBuilder(lombok.eclipse.handlers.HandleBuilder) ArrayList(java.util.ArrayList) ToString(lombok.ToString) FieldDeclaration(org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) QualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference) ParameterizedQualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference) EclipseSingularizer(lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer) TypeReference(org.eclipse.jdt.internal.compiler.ast.TypeReference) ParameterizedSingleTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference) QualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference) ParameterizedQualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference) SingleTypeReference(org.eclipse.jdt.internal.compiler.ast.SingleTypeReference) MethodDeclaration(org.eclipse.jdt.internal.compiler.ast.MethodDeclaration) AbstractMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration) ParameterizedQualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference) Included(lombok.core.handlers.InclusionExclusionUtils.Included) MarkerAnnotation(org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation) Annotation(org.eclipse.jdt.internal.compiler.ast.Annotation) ParameterizedSingleTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference) SingleTypeReference(org.eclipse.jdt.internal.compiler.ast.SingleTypeReference) SingularData(lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData) EclipseNode(lombok.eclipse.EclipseNode) ToString(lombok.ToString) TypeDeclaration(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)

Example 3 with Included

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);
}
Also used : Included(lombok.core.handlers.InclusionExclusionUtils.Included) ToString(lombok.ToString) FieldAccess(lombok.core.handlers.HandlerUtil.FieldAccess)

Example 4 with Included

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.");
        }
    }
}
Also used : MemberExistsResult(lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult) JCFieldAccess(com.sun.tools.javac.tree.JCTree.JCFieldAccess) Builder(lombok.Builder) ListBuffer(com.sun.tools.javac.util.ListBuffer) ArrayList(java.util.ArrayList) JCTypeApply(com.sun.tools.javac.tree.JCTree.JCTypeApply) JavacSingularizer(lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer) ToString(lombok.ToString) Name(com.sun.tools.javac.util.Name) JavacNode(lombok.javac.JavacNode) JCArrayTypeTree(com.sun.tools.javac.tree.JCTree.JCArrayTypeTree) JCClassDecl(com.sun.tools.javac.tree.JCTree.JCClassDecl) JCIdent(com.sun.tools.javac.tree.JCTree.JCIdent) JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) JavacTreeMaker(lombok.javac.JavacTreeMaker) Included(lombok.core.handlers.InclusionExclusionUtils.Included) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl) JCTypeParameter(com.sun.tools.javac.tree.JCTree.JCTypeParameter) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) SingularData(lombok.javac.handlers.JavacSingularsRecipes.SingularData) ToString(lombok.ToString)

Example 5 with Included

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());
}
Also used : Included(lombok.core.handlers.InclusionExclusionUtils.Included) EqualsAndHashCode(lombok.EqualsAndHashCode) JCFieldAccess(com.sun.tools.javac.tree.JCTree.JCFieldAccess) FieldAccess(lombok.core.handlers.HandlerUtil.FieldAccess)

Aggregations

Included (lombok.core.handlers.InclusionExclusionUtils.Included)10 ToString (lombok.ToString)7 JCFieldAccess (com.sun.tools.javac.tree.JCTree.JCFieldAccess)4 ArrayList (java.util.ArrayList)4 Builder (lombok.Builder)4 FieldAccess (lombok.core.handlers.HandlerUtil.FieldAccess)4 EqualsAndHashCode (lombok.EqualsAndHashCode)3 JavacNode (lombok.javac.JavacNode)3 Annotation (org.eclipse.jdt.internal.compiler.ast.Annotation)3 JCClassDecl (com.sun.tools.javac.tree.JCTree.JCClassDecl)2 JCExpression (com.sun.tools.javac.tree.JCTree.JCExpression)2 JCMethodDecl (com.sun.tools.javac.tree.JCTree.JCMethodDecl)2 JCTypeApply (com.sun.tools.javac.tree.JCTree.JCTypeApply)2 JCTypeParameter (com.sun.tools.javac.tree.JCTree.JCTypeParameter)2 JCVariableDecl (com.sun.tools.javac.tree.JCTree.JCVariableDecl)2 ListBuffer (com.sun.tools.javac.util.ListBuffer)2 Name (com.sun.tools.javac.util.Name)2 EclipseNode (lombok.eclipse.EclipseNode)2 EclipseSingularizer (lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer)2 SingularData (lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData)2