Package groovy.transform.builder

Source Code of groovy.transform.builder.SimpleStrategy

/*
* Copyright 2003-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package groovy.transform.builder;

import org.codehaus.groovy.ast.AnnotatedNode;
import org.codehaus.groovy.ast.AnnotationNode;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.Parameter;
import org.codehaus.groovy.transform.AbstractASTTransformation;
import org.codehaus.groovy.transform.BuilderASTTransformation;
import org.objectweb.asm.Opcodes;

import java.util.ArrayList;
import java.util.List;

import static org.codehaus.groovy.ast.tools.GeneralUtils.assignX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.block;
import static org.codehaus.groovy.ast.tools.GeneralUtils.fieldX;
import static org.codehaus.groovy.ast.tools.GeneralUtils.getInstancePropertyFields;
import static org.codehaus.groovy.ast.tools.GeneralUtils.param;
import static org.codehaus.groovy.ast.tools.GeneralUtils.params;
import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS;
import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
import static org.codehaus.groovy.ast.tools.GenericsUtils.newClass;
import static org.codehaus.groovy.transform.BuilderASTTransformation.NO_EXCEPTIONS;

/**
* This strategy is used with the {@link Builder} AST transform to modify your Groovy objects so that the
* setter methods for properties return the original object, thus allowing chained usage of the setters.
*
* You use it as follows:
* <pre>
* import groovy.transform.builder.*
*
* {@code @Builder}(builderStrategy=SimpleStrategy)
* class Person {
*     String firstName
*     String lastName
*     int age
* }
* def person = new Person().setFirstName("Robert").setLastName("Lewandowski").setAge(21)
* assert person.firstName == "Robert"
* assert person.lastName == "Lewandowski"
* assert person.age == 21
* </pre>
* The {@code prefix} annotation attribute can be used to create setters with a different naming convention, e.g. with the prefix set to the empty String, you would use your setters as follows:
* <pre>
* def p1 = new Person().firstName("Robert").lastName("Lewandowski").age(21)
* </pre>
* or using a prefix of 'with':
* <pre>
* def p2 = new Person().withFirstName("Robert").withLastName("Lewandowski").withAge(21)
* </pre>
* When using the default prefix of "set", Groovy's normal setters will be replaced by the chained versions. When using
* a custom prefix, Groovy's unchained setters will still be available for use in the normal unchained fashion.
*
* The other annotation attributes for the {@code @Builder} transform for configuring the building process aren't applicable for this strategy.
*
* @author Paul King
*/
public class SimpleStrategy extends BuilderASTTransformation.AbstractBuilderStrategy {
    public void build(BuilderASTTransformation transform, AnnotatedNode annotatedNode, AnnotationNode anno) {
        if (!(annotatedNode instanceof ClassNode)) {
            transform.addError("Error during " + BuilderASTTransformation.MY_TYPE_NAME + " processing: building for " +
                    annotatedNode.getClass().getSimpleName() + " not supported by " + getClass().getSimpleName(), annotatedNode);
            return;
        }
        ClassNode buildee = (ClassNode) annotatedNode;
        if (unsupportedAttribute(transform, anno, "builderClassName")) return;
        if (unsupportedAttribute(transform, anno, "buildMethodName")) return;
        if (unsupportedAttribute(transform, anno, "builderMethodName")) return;
        if (unsupportedAttribute(transform, anno, "forClass")) return;

        List<String> excludes = new ArrayList<String>();
        List<String> includes = new ArrayList<String>();
        if (!getIncludeExclude(transform, anno, buildee, excludes, includes)) return;
        String prefix = transform.getMemberStringValue(anno, "prefix", "set");
        List<FieldNode> fields = getInstancePropertyFields(buildee);
        for (String name : includes) {
            checkKnownField(transform, anno, name, fields);
        }
        for (FieldNode field : fields) {
            String fieldName = field.getName();
            if (!AbstractASTTransformation.shouldSkip(fieldName, excludes, includes)) {
                String methodName = getSetterName(prefix, fieldName);
                Parameter parameter = param(field.getType(), fieldName);
                buildee.addMethod(methodName, Opcodes.ACC_PUBLIC, newClass(buildee), params(parameter), NO_EXCEPTIONS, block(
                                stmt(assignX(fieldX(field), varX(parameter))),
                                returnS(varX("this")))
                );
            }
        }
    }
}
TOP

Related Classes of groovy.transform.builder.SimpleStrategy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.