Package org.springframework.roo.classpath.javaparser.details

Source Code of org.springframework.roo.classpath.javaparser.details.JavaParserFieldMetadataBuilder

package org.springframework.roo.classpath.javaparser.details;

import japa.parser.ASTHelper;
import japa.parser.JavaParser;
import japa.parser.ParseException;
import japa.parser.ast.CompilationUnit;
import japa.parser.ast.body.BodyDeclaration;
import japa.parser.ast.body.FieldDeclaration;
import japa.parser.ast.body.TypeDeclaration;
import japa.parser.ast.body.VariableDeclarator;
import japa.parser.ast.expr.AnnotationExpr;
import japa.parser.ast.expr.Expression;
import japa.parser.ast.expr.NameExpr;
import japa.parser.ast.expr.ObjectCreationExpr;
import japa.parser.ast.type.ClassOrInterfaceType;
import japa.parser.ast.type.Type;

import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.springframework.roo.classpath.details.FieldMetadata;
import org.springframework.roo.classpath.details.FieldMetadataBuilder;
import org.springframework.roo.classpath.details.annotations.AnnotationMetadata;
import org.springframework.roo.classpath.javaparser.CompilationUnitServices;
import org.springframework.roo.classpath.javaparser.JavaParserUtils;
import org.springframework.roo.model.Builder;
import org.springframework.roo.model.JavaSymbolName;
import org.springframework.roo.model.JavaType;

/**
* Java Parser implementation of {@link FieldMetadata}.
*
* @author Ben Alex
* @since 1.0
*/
public class JavaParserFieldMetadataBuilder implements Builder<FieldMetadata> {

    public static void addField(
            final CompilationUnitServices compilationUnitServices,
            final List<BodyDeclaration> members, final FieldMetadata field) {
        Validate.notNull(compilationUnitServices,
                "Flushable compilation unit services required");
        Validate.notNull(members, "Members required");
        Validate.notNull(field, "Field required");

        JavaParserUtils.importTypeIfRequired(
                compilationUnitServices.getEnclosingTypeName(),
                compilationUnitServices.getImports(), field.getFieldType());
        final Type initType = JavaParserUtils.getResolvedName(
                compilationUnitServices.getEnclosingTypeName(),
                field.getFieldType(), compilationUnitServices);
        ClassOrInterfaceType finalType = JavaParserUtils
                .getClassOrInterfaceType(initType);

        final FieldDeclaration newField = ASTHelper.createFieldDeclaration(
                JavaParserUtils.getJavaParserModifier(field.getModifier()),
                initType, field.getFieldName().getSymbolName());

        // Add parameterized types for the field type (not initializer)
        if (field.getFieldType().getParameters().size() > 0) {
            final List<Type> fieldTypeArgs = new ArrayList<Type>();
            finalType.setTypeArgs(fieldTypeArgs);
            for (final JavaType parameter : field.getFieldType()
                    .getParameters()) {
                fieldTypeArgs.add(JavaParserUtils.importParametersForType(
                        compilationUnitServices.getEnclosingTypeName(),
                        compilationUnitServices.getImports(), parameter));
            }
        }

        final List<VariableDeclarator> vars = newField.getVariables();
        Validate.notEmpty(vars,
                "Expected ASTHelper to have provided a single VariableDeclarator");
        Validate.isTrue(vars.size() == 1,
                "Expected ASTHelper to have provided a single VariableDeclarator");
        final VariableDeclarator vd = vars.iterator().next();

        if (StringUtils.isNotBlank(field.getFieldInitializer())) {
            // There is an initializer.
            // We need to make a fake field that we can have JavaParser parse.
            // Easiest way to do that is to build a simple source class
            // containing the required field and re-parse it.
            final StringBuilder sb = new StringBuilder();
            sb.append("class TemporaryClass {\n");
            sb.append("  private " + field.getFieldType() + " "
                    + field.getFieldName() + " = "
                    + field.getFieldInitializer() + ";\n");
            sb.append("}\n");
            final ByteArrayInputStream bais = new ByteArrayInputStream(sb
                    .toString().getBytes());
            CompilationUnit ci;
            try {
                ci = JavaParser.parse(bais);
            }
            catch (final ParseException pe) {
                throw new IllegalStateException(
                        "Illegal state: JavaParser did not parse correctly", pe);
            }
            final List<TypeDeclaration> types = ci.getTypes();
            if (types == null || types.size() != 1) {
                throw new IllegalArgumentException("Field member invalid");
            }
            final TypeDeclaration td = types.get(0);
            final List<BodyDeclaration> bodyDeclarations = td.getMembers();
            if (bodyDeclarations == null || bodyDeclarations.size() != 1) {
                throw new IllegalStateException(
                        "Illegal state: JavaParser did not return body declarations correctly");
            }
            final BodyDeclaration bd = bodyDeclarations.get(0);
            if (!(bd instanceof FieldDeclaration)) {
                throw new IllegalStateException(
                        "Illegal state: JavaParser did not return a field declaration correctly");
            }
            final FieldDeclaration fd = (FieldDeclaration) bd;
            if (fd.getVariables() == null || fd.getVariables().size() != 1) {
                throw new IllegalStateException(
                        "Illegal state: JavaParser did not return a field declaration correctly");
            }

            final Expression init = fd.getVariables().get(0).getInit();

            // Resolve imports (ROO-1505)
            if (init instanceof ObjectCreationExpr) {
                final ObjectCreationExpr ocr = (ObjectCreationExpr) init;
                final JavaType typeToImport = JavaParserUtils.getJavaTypeNow(
                        compilationUnitServices, ocr.getType(), null);
                final NameExpr nameExpr = JavaParserUtils.importTypeIfRequired(
                        compilationUnitServices.getEnclosingTypeName(),
                        compilationUnitServices.getImports(), typeToImport);
                final ClassOrInterfaceType classOrInterfaceType = JavaParserUtils
                        .getClassOrInterfaceType(nameExpr);
                ocr.setType(classOrInterfaceType);

                if (typeToImport.getParameters().size() > 0) {
                    final List<Type> initTypeArgs = new ArrayList<Type>();
                    finalType.setTypeArgs(initTypeArgs);
                    for (final JavaType parameter : typeToImport
                            .getParameters()) {
                        initTypeArgs.add(JavaParserUtils.importParametersForType(
                                compilationUnitServices.getEnclosingTypeName(),
                                compilationUnitServices.getImports(), parameter));
                    }
                    classOrInterfaceType.setTypeArgs(initTypeArgs);
                }
            }

            vd.setInit(init);
        }

        // Add annotations
        final List<AnnotationExpr> annotations = new ArrayList<AnnotationExpr>();
        newField.setAnnotations(annotations);
        for (final AnnotationMetadata annotation : field.getAnnotations()) {
            JavaParserAnnotationMetadataBuilder.addAnnotationToList(
                    compilationUnitServices, annotations, annotation);
        }

        // Locate where to add this field; also verify if this field already
        // exists
        int nextFieldIndex = 0;
        int i = -1;
        for (final BodyDeclaration bd : members) {
            i++;
            if (bd instanceof FieldDeclaration) {
                // Next field should appear after this current field
                nextFieldIndex = i + 1;
                final FieldDeclaration bdf = (FieldDeclaration) bd;
                for (final VariableDeclarator v : bdf.getVariables()) {
                    Validate.isTrue(!field.getFieldName().getSymbolName()
                            .equals(v.getId().getName()), "A field with name '"
                            + field.getFieldName().getSymbolName()
                            + "' already exists");
                }
            }
        }

        // Add the field to the compilation unit
        members.add(nextFieldIndex, newField);
    }

    public static JavaParserFieldMetadataBuilder getInstance(
            final String declaredByMetadataId,
            final FieldDeclaration fieldDeclaration,
            final VariableDeclarator var,
            final CompilationUnitServices compilationUnitServices,
            final Set<JavaSymbolName> typeParameters) {
        return new JavaParserFieldMetadataBuilder(declaredByMetadataId,
                fieldDeclaration, var, compilationUnitServices, typeParameters);
    }

    public static void removeField(
            final CompilationUnitServices compilationUnitServices,
            final List<BodyDeclaration> members, final JavaSymbolName fieldName) {
        Validate.notNull(compilationUnitServices,
                "Flushable compilation unit services required");
        Validate.notNull(members, "Members required");
        Validate.notNull(fieldName, "Field name to remove is required");

        // Locate the field
        int i = -1;
        int toDelete = -1;
        for (final BodyDeclaration bd : members) {
            i++;
            if (bd instanceof FieldDeclaration) {
                final FieldDeclaration fieldDeclaration = (FieldDeclaration) bd;
                for (final VariableDeclarator var : fieldDeclaration
                        .getVariables()) {
                    if (var.getId().getName().equals(fieldName.getSymbolName())) {
                        toDelete = i;
                        break;
                    }
                }
            }
        }

        Validate.isTrue(toDelete > -1, "Could not locate field '%s' to delete",
                fieldName);

        // Do removal outside iteration of body declaration members, to avoid
        // concurrent modification exceptions
        members.remove(toDelete);
    }

    private final List<AnnotationMetadata> annotations = new ArrayList<AnnotationMetadata>();
    private final String declaredByMetadataId;
    private String fieldInitializer;

    private final JavaSymbolName fieldName;

    private JavaType fieldType;

    private final int modifier;

    private JavaParserFieldMetadataBuilder(final String declaredByMetadataId,
            final FieldDeclaration fieldDeclaration,
            final VariableDeclarator var,
            final CompilationUnitServices compilationUnitServices,
            final Set<JavaSymbolName> typeParameters) {
        Validate.notNull(declaredByMetadataId,
                "Declared by metadata ID required");
        Validate.notNull(fieldDeclaration, "Field declaration is mandatory");
        Validate.notNull(var, "Variable declarator required");
        Validate.isTrue(fieldDeclaration.getVariables().contains(var),
                "Cannot request a variable not already in the field declaration");
        Validate.notNull(compilationUnitServices,
                "Compilation unit services are required");

        // Convert Java Parser modifier into JDK modifier
        modifier = JavaParserUtils.getJdkModifier(fieldDeclaration
                .getModifiers());

        this.declaredByMetadataId = declaredByMetadataId;

        final Type type = fieldDeclaration.getType();
        fieldType = JavaParserUtils.getJavaType(compilationUnitServices, type,
                typeParameters);

        // Convert into an array if this variable ID uses array notation
        if (var.getId().getArrayCount() > 0) {
            fieldType = new JavaType(fieldType.getFullyQualifiedTypeName(), var
                    .getId().getArrayCount() + fieldType.getArray(),
                    fieldType.getDataType(), fieldType.getArgName(),
                    fieldType.getParameters());
        }

        fieldName = new JavaSymbolName(var.getId().getName());

        // Lookup initializer, if one was requested and easily determinable
        final Expression e = var.getInit();
        if (e != null) {
            fieldInitializer = e.toString();
        }

        final List<AnnotationExpr> annotations = fieldDeclaration
                .getAnnotations();
        if (annotations != null) {
            for (final AnnotationExpr annotation : annotations) {
                this.annotations.add(JavaParserAnnotationMetadataBuilder
                        .getInstance(annotation, compilationUnitServices)
                        .build());
            }
        }
    }

    public FieldMetadata build() {
        final FieldMetadataBuilder fieldMetadataBuilder = new FieldMetadataBuilder(
                declaredByMetadataId);
        fieldMetadataBuilder.setAnnotations(annotations);
        fieldMetadataBuilder.setFieldInitializer(fieldInitializer);
        fieldMetadataBuilder.setFieldName(fieldName);
        fieldMetadataBuilder.setFieldType(fieldType);
        fieldMetadataBuilder.setModifier(modifier);
        return fieldMetadataBuilder.build();
    }
}
TOP

Related Classes of org.springframework.roo.classpath.javaparser.details.JavaParserFieldMetadataBuilder

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.