All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.redhat.ceylon.compiler.java.loader.AnnotationLoader Maven / Gradle / Ivy

There is a newer version: 1.3.3
Show newest version
/*
 * Copyright Red Hat Inc. and/or its affiliates and other contributors
 * as indicated by the authors tag. All rights reserved.
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU General Public License version 2.
 * 
 * This particular file is subject to the "Classpath" exception as provided in the 
 * LICENSE file that accompanied this code.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT A
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License,
 * along with this distribution; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA  02110-1301, USA.
 */

package com.redhat.ceylon.compiler.java.loader;

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

import com.redhat.ceylon.compiler.java.codegen.AnnotationArgument;
import com.redhat.ceylon.compiler.java.codegen.AnnotationConstructorParameter;
import com.redhat.ceylon.compiler.java.codegen.AnnotationFieldName;
import com.redhat.ceylon.compiler.java.codegen.AnnotationInvocation;
import com.redhat.ceylon.compiler.java.codegen.AnnotationTerm;
import com.redhat.ceylon.compiler.java.codegen.BooleanLiteralAnnotationTerm;
import com.redhat.ceylon.compiler.java.codegen.CharacterLiteralAnnotationTerm;
import com.redhat.ceylon.compiler.java.codegen.CollectionLiteralAnnotationTerm;
import com.redhat.ceylon.compiler.java.codegen.Decl;
import com.redhat.ceylon.compiler.java.codegen.DeclarationLiteralAnnotationTerm;
import com.redhat.ceylon.compiler.java.codegen.FloatLiteralAnnotationTerm;
import com.redhat.ceylon.compiler.java.codegen.IntegerLiteralAnnotationTerm;
import com.redhat.ceylon.compiler.java.codegen.InvocationAnnotationTerm;
import com.redhat.ceylon.compiler.java.codegen.LiteralAnnotationTerm;
import com.redhat.ceylon.compiler.java.codegen.Naming;
import com.redhat.ceylon.compiler.java.codegen.ObjectLiteralAnnotationTerm;
import com.redhat.ceylon.compiler.java.codegen.ParameterAnnotationTerm;
import com.redhat.ceylon.compiler.java.codegen.StringLiteralAnnotationTerm;
import com.redhat.ceylon.model.loader.AbstractModelLoader;
import com.redhat.ceylon.model.loader.ModelLoader.DeclarationType;
import com.redhat.ceylon.model.loader.mirror.AnnotatedMirror;
import com.redhat.ceylon.model.loader.mirror.AnnotationMirror;
import com.redhat.ceylon.model.loader.mirror.ClassMirror;
import com.redhat.ceylon.model.loader.mirror.MethodMirror;
import com.redhat.ceylon.model.loader.mirror.TypeMirror;
import com.redhat.ceylon.model.loader.model.AnnotationProxyClass;
import com.redhat.ceylon.model.loader.model.AnnotationProxyMethod;
import com.redhat.ceylon.model.loader.model.LazyFunction;
import com.redhat.ceylon.model.typechecker.model.Class;
import com.redhat.ceylon.model.typechecker.model.Function;
import com.redhat.ceylon.model.typechecker.model.Module;
import com.redhat.ceylon.model.typechecker.model.Parameter;
import com.redhat.ceylon.model.typechecker.model.Type;
import com.redhat.ceylon.model.typechecker.model.Unit;

/**
 *
 * @author Stéphane Épardaud 
 */
public class AnnotationLoader {

    private AbstractModelLoader modelLoader;
    private Unit typeFactory;

    public AnnotationLoader(AbstractModelLoader modelLoader, Unit unit) {
        this.modelLoader = modelLoader;
        this.typeFactory = unit;
    }

    public void setAnnotationConstructor(LazyFunction method, MethodMirror meth) {
        AnnotationInvocation ai = loadAnnotationInvocation(method, method.classMirror, meth);
        if (ai != null) {
            loadAnnotationConstructorDefaultedParameters(method, meth, ai);
            ai.setConstructorDeclaration(method);
            method.setAnnotationConstructor(ai);
        }
    }
    
    private AnnotationInvocation loadAnnotationInvocation(
            LazyFunction method, 
            AnnotatedMirror annoInstMirror, MethodMirror meth) {
        AnnotationInvocation ai = null;
        AnnotationMirror annotationInvocationAnnotation = null;
        
        List annotationTree = getAnnotationArrayValue(annoInstMirror, AbstractModelLoader.CEYLON_ANNOTATION_INSTANTIATION_TREE_ANNOTATION, "value");
        if (annotationTree != null
                && !annotationTree.isEmpty()) {
            annotationInvocationAnnotation = annotationTree.get(0);
        } else {
            annotationInvocationAnnotation = annoInstMirror.getAnnotation(AbstractModelLoader.CEYLON_ANNOTATION_INSTANTIATION_ANNOTATION);
        }
        //stringValueAnnotation = annoInstMirror.getAnnotation(CEYLON_STRING_VALUE_ANNOTATION);
        if (annotationInvocationAnnotation != null) {
            ai = new AnnotationInvocation();
            setPrimaryFromAnnotationInvocationAnnotation(annotationInvocationAnnotation, ai);
            loadAnnotationInvocationArguments(new ArrayList(2), method, ai, annotationInvocationAnnotation, annotationTree, annoInstMirror);
        }
        return ai;
    }
    
    private void loadAnnotationInvocationArguments(
            List path,
            LazyFunction method,
            AnnotationInvocation ai, AnnotationMirror annotationInvocationAnnotation,
            List annotationTree, 
            AnnotatedMirror dpm) {
        @SuppressWarnings("unchecked")
        List argumentCodes = (List)annotationInvocationAnnotation.getValue(AbstractModelLoader.CEYLON_ANNOTATION_INSTANTIATION_ARGUMENTS_MEMBER);
        if(argumentCodes != null){
            for (int ii = 0; ii < argumentCodes.size(); ii++) {
                short code = argumentCodes.get(ii);
                AnnotationArgument argument = new AnnotationArgument();
                Parameter classParameter = ai.getParameters().get(ii);
                argument.setParameter(classParameter);
                path.add(argument);
                argument.setTerm(loadAnnotationArgumentTerm(path, method, ai, classParameter, annotationTree, dpm, code));
                path.remove(path.size()-1);
                ai.getAnnotationArguments().add(argument);
            }
        }
    }

    private AnnotationTerm decode(Module moduleScope, List sourceParameters, AnnotationInvocation info, 
            Parameter parameter, 
            AnnotatedMirror dpm, List path, int code) {
        AnnotationTerm result;
        if (code == Short.MIN_VALUE) {
            return findLiteralAnnotationTerm(moduleScope, path, parameter, dpm);
        } else if (code < 0) {
            InvocationAnnotationTerm invocation = new InvocationAnnotationTerm();
            result = invocation;
        } else if (code >= 0 && code < 512) {
            ParameterAnnotationTerm parameterArgument = new ParameterAnnotationTerm();
            boolean spread = false;
            if (code >= 256) {
                spread = true;
                code-=256;
            }
            
            parameterArgument.setSpread(spread);
            Parameter sourceParameter = sourceParameters.get(code);
            parameterArgument.setSourceParameter(sourceParameter);
            //result.setTargetParameter(sourceParameter);
            result = parameterArgument;
        } else {
            throw new RuntimeException();
        }
        return result;
    }
    
    private AnnotationTerm loadAnnotationArgumentTerm(
            List path,
            LazyFunction method,
            AnnotationInvocation ai, Parameter parameter,
            List annotationTree,
            AnnotatedMirror dpm,
            short code) {
        if (code < 0 && code != Short.MIN_VALUE) {
            AnnotationMirror i = annotationTree.get(-code);
            AnnotationInvocation nested = new AnnotationInvocation();
            setPrimaryFromAnnotationInvocationAnnotation(i, nested);
            loadAnnotationInvocationArguments(path, method, nested, i, annotationTree, dpm);
            InvocationAnnotationTerm term = new InvocationAnnotationTerm();
            term.setInstantiation(nested);
            return term;
        } else {
            AnnotationTerm term = decode(Decl.getModuleContainer(method), method.getFirstParameterList().getParameters(), ai, parameter, dpm, path, code);
            return term;
        }
    }
    private void setPrimaryFromAnnotationInvocationAnnotation(AnnotationMirror annotationInvocationAnnotation,
            AnnotationInvocation ai) {
        TypeMirror annotationType = (TypeMirror)annotationInvocationAnnotation.getValue(AbstractModelLoader.CEYLON_ANNOTATION_INSTANTIATION_ANNOTATION_MEMBER);
        ClassMirror annotationClassMirror = annotationType.getDeclaredClass();
        Module module = modelLoader.findModuleForClassMirror(annotationClassMirror);
        if (annotationClassMirror.getAnnotation(AbstractModelLoader.CEYLON_METHOD_ANNOTATION) != null) {
            ai.setPrimary((Function)modelLoader.convertToDeclaration(module, annotationClassMirror, DeclarationType.VALUE));
        } else {
            ai.setPrimary((Class)modelLoader.convertToDeclaration(module, annotationClassMirror, DeclarationType.TYPE));
        }
    }
    
    private void loadAnnotationConstructorDefaultedParameters(
            LazyFunction method, MethodMirror meth, AnnotationInvocation ai) {
        for (Parameter ctorParam : method.getFirstParameterList().getParameters()) {
            AnnotationConstructorParameter acp = new AnnotationConstructorParameter();
            acp.setParameter(ctorParam);
            if (ctorParam.isDefaulted()) {
                acp.setDefaultArgument(
                        loadAnnotationConstructorDefaultedParameter(method, meth, ctorParam, acp));
            }
            ai.addConstructorParameter(acp);
        }
    }
    private AnnotationTerm loadAnnotationConstructorDefaultedParameter(
            LazyFunction method, 
            MethodMirror meth,
            Parameter ctorParam, AnnotationConstructorParameter acp) {
        // Find the method mirror for the DPM
        for (MethodMirror mm : method.classMirror.getDirectMethods()) {
            if (mm.getName().equals(Naming.getDefaultedParamMethodName(method, ctorParam))) {
                // Create the appropriate AnnotationTerm
                if (mm.getAnnotation(AbstractModelLoader.CEYLON_ANNOTATION_INSTANTIATION_ANNOTATION) != null) {
                    // If the DPM has a @AnnotationInstantiation 
                    // then it must be an invocation term so recurse
                    InvocationAnnotationTerm invocationTerm = new InvocationAnnotationTerm();
                    invocationTerm.setInstantiation(loadAnnotationInvocation(method, mm, meth));
                    return invocationTerm;
                } else {
                    return loadLiteralAnnotationTerm(method, ctorParam, mm);
                }
            }
        }
        return null;
    }
    /** 
     * Loads a LiteralAnnotationTerm according to the presence of 
     * 
    *
  • {@code @StringValue}
  • {@code @IntegerValue}
  • etc *
* @param ctorParam * */ private LiteralAnnotationTerm loadLiteralAnnotationTerm(LazyFunction method, Parameter parameter, AnnotatedMirror mm) { // FIXME: store iterable info somewhere else boolean singleValue = !typeFactory.isIterableType(parameter.getType()) || parameter.getType().isString(); AnnotationMirror valueAnnotation = mm.getAnnotation(AbstractModelLoader.CEYLON_STRING_VALUE_ANNOTATION); if (valueAnnotation != null) { return readStringValuesAnnotation(valueAnnotation, singleValue); } valueAnnotation = mm.getAnnotation(AbstractModelLoader.CEYLON_INTEGER_VALUE_ANNOTATION); if (valueAnnotation != null) { return readIntegerValuesAnnotation(valueAnnotation, singleValue); } valueAnnotation = mm.getAnnotation(AbstractModelLoader.CEYLON_BOOLEAN_VALUE_ANNOTATION); if (valueAnnotation != null) { return readBooleanValuesAnnotation(valueAnnotation, singleValue); } valueAnnotation = mm.getAnnotation(AbstractModelLoader.CEYLON_DECLARATION_VALUE_ANNOTATION); if (valueAnnotation != null) { return readDeclarationValuesAnnotation(valueAnnotation, singleValue); } valueAnnotation = mm.getAnnotation(AbstractModelLoader.CEYLON_OBJECT_VALUE_ANNOTATION); if (valueAnnotation != null) { return readObjectValuesAnnotation(Decl.getModuleContainer(method), valueAnnotation, singleValue); } valueAnnotation = mm.getAnnotation(AbstractModelLoader.CEYLON_CHARACTER_VALUE_ANNOTATION); if (valueAnnotation != null) { return readCharacterValuesAnnotation(valueAnnotation, singleValue); } valueAnnotation = mm.getAnnotation(AbstractModelLoader.CEYLON_FLOAT_VALUE_ANNOTATION); if (valueAnnotation != null) { return readFloatValuesAnnotation(valueAnnotation, singleValue); } return null; } /** * Searches the {@code @*Exprs} for one containing a {@code @*Value} * whose {@code name} matches the given namePath returning the first * match, or null. */ private LiteralAnnotationTerm findLiteralAnnotationTerm(Module moduleScope, List namePath, Parameter parameter, AnnotatedMirror mm) { // FIXME: store info somewhere else boolean singeValue = !typeFactory.isIterableType(parameter.getType()) || parameter.getType().isString(); final String name = Naming.getAnnotationFieldName(namePath); AnnotationMirror exprsAnnotation = mm.getAnnotation(AbstractModelLoader.CEYLON_STRING_EXPRS_ANNOTATION); if (exprsAnnotation != null) { for (AnnotationMirror valueAnnotation : getAnnotationAnnoValues(exprsAnnotation, "value")) { String path = (String)valueAnnotation.getValue("name"); if (name.equals(path)) { return readStringValuesAnnotation(valueAnnotation, singeValue); } } } exprsAnnotation = mm.getAnnotation(AbstractModelLoader.CEYLON_INTEGER_EXPRS_ANNOTATION); if (exprsAnnotation != null) { for (AnnotationMirror valueAnnotation : getAnnotationAnnoValues(exprsAnnotation, "value")) { String path = (String)valueAnnotation.getValue("name"); if (name.equals(path)) { return readIntegerValuesAnnotation(valueAnnotation, singeValue); } } } exprsAnnotation = mm.getAnnotation(AbstractModelLoader.CEYLON_BOOLEAN_EXPRS_ANNOTATION); if (exprsAnnotation != null) { for (AnnotationMirror valueAnnotation : getAnnotationAnnoValues(exprsAnnotation, "value")) { String path = (String)valueAnnotation.getValue("name"); if (name.equals(path)) { return readBooleanValuesAnnotation(valueAnnotation, singeValue); } } } exprsAnnotation = mm.getAnnotation(AbstractModelLoader.CEYLON_DECLARATION_EXPRS_ANNOTATION); if (exprsAnnotation != null) { for (AnnotationMirror valueAnnotation : getAnnotationAnnoValues(exprsAnnotation, "value")) { String path = (String)valueAnnotation.getValue("name"); if (name.equals(path)) { return readDeclarationValuesAnnotation(valueAnnotation, singeValue); } } } exprsAnnotation = mm.getAnnotation(AbstractModelLoader.CEYLON_OBJECT_EXPRS_ANNOTATION); if (exprsAnnotation != null) { for (AnnotationMirror valueAnnotation : getAnnotationAnnoValues(exprsAnnotation, "value")) { String path = (String)valueAnnotation.getValue("name"); if (name.equals(path)) { return readObjectValuesAnnotation(moduleScope, valueAnnotation, singeValue); } } } exprsAnnotation = mm.getAnnotation(AbstractModelLoader.CEYLON_CHARACTER_EXPRS_ANNOTATION); if (exprsAnnotation != null) { for (AnnotationMirror valueAnnotation : getAnnotationAnnoValues(exprsAnnotation, "value")) { String path = (String)valueAnnotation.getValue("name"); if (name.equals(path)) { return readCharacterValuesAnnotation(valueAnnotation, singeValue); } } } exprsAnnotation = mm.getAnnotation(AbstractModelLoader.CEYLON_FLOAT_EXPRS_ANNOTATION); if (exprsAnnotation != null) { for (AnnotationMirror valueAnnotation : getAnnotationAnnoValues(exprsAnnotation, "value")) { String path = (String)valueAnnotation.getValue("name"); if (name.equals(path)) { return readFloatValuesAnnotation(valueAnnotation, singeValue); } } } return null; } private LiteralAnnotationTerm readObjectValuesAnnotation( Module moduleScope, AnnotationMirror valueAnnotation, boolean singleValue) { if (singleValue) { TypeMirror klass = getAnnotationClassValues(valueAnnotation, "value").get(0); Type type = modelLoader.obtainType(moduleScope, klass, null, null, null); ObjectLiteralAnnotationTerm term = new ObjectLiteralAnnotationTerm(type); return term; } else { CollectionLiteralAnnotationTerm result = new CollectionLiteralAnnotationTerm(ObjectLiteralAnnotationTerm.FACTORY); for (TypeMirror klass : getAnnotationClassValues(valueAnnotation, "value")) { Type type = modelLoader.obtainType(moduleScope, klass, null, null, null); result.addElement(new ObjectLiteralAnnotationTerm(type)); } return result; } } private LiteralAnnotationTerm readStringValuesAnnotation( AnnotationMirror valueAnnotation, boolean singleValue) { if (singleValue) { String value = getAnnotationStringValues(valueAnnotation, "value").get(0); StringLiteralAnnotationTerm term = new StringLiteralAnnotationTerm(value); return term; } else { CollectionLiteralAnnotationTerm result = new CollectionLiteralAnnotationTerm(StringLiteralAnnotationTerm.FACTORY); for (String value : getAnnotationStringValues(valueAnnotation, "value")) { result.addElement(new StringLiteralAnnotationTerm(value)); } return result; } } private LiteralAnnotationTerm readIntegerValuesAnnotation( AnnotationMirror valueAnnotation, boolean singleValue) { if (singleValue) { Long value = getAnnotationLongValues(valueAnnotation, "value").get(0); IntegerLiteralAnnotationTerm term = new IntegerLiteralAnnotationTerm(value); return term; } else { CollectionLiteralAnnotationTerm result = new CollectionLiteralAnnotationTerm(IntegerLiteralAnnotationTerm.FACTORY); for (Long value : getAnnotationLongValues(valueAnnotation, "value")) { result.addElement(new IntegerLiteralAnnotationTerm(value)); } return result; } } private LiteralAnnotationTerm readCharacterValuesAnnotation( AnnotationMirror valueAnnotation, boolean singleValue) { if (singleValue) { Integer value = getAnnotationIntegerValues(valueAnnotation, "value").get(0); CharacterLiteralAnnotationTerm term = new CharacterLiteralAnnotationTerm(value); return term; } else { CollectionLiteralAnnotationTerm result = new CollectionLiteralAnnotationTerm(CharacterLiteralAnnotationTerm.FACTORY); for (Integer value : getAnnotationIntegerValues(valueAnnotation, "value")) { result.addElement(new CharacterLiteralAnnotationTerm(value)); } return result; } } private LiteralAnnotationTerm readFloatValuesAnnotation( AnnotationMirror valueAnnotation, boolean singleValue) { if (singleValue) { Double value = getAnnotationDoubleValues(valueAnnotation, "value").get(0); FloatLiteralAnnotationTerm term = new FloatLiteralAnnotationTerm(value); return term; } else { CollectionLiteralAnnotationTerm result = new CollectionLiteralAnnotationTerm(FloatLiteralAnnotationTerm.FACTORY); for (Double value : getAnnotationDoubleValues(valueAnnotation, "value")) { result.addElement(new FloatLiteralAnnotationTerm(value)); } return result; } } private LiteralAnnotationTerm readBooleanValuesAnnotation( AnnotationMirror valueAnnotation, boolean singleValue) { if (singleValue) { boolean value = getAnnotationBooleanValues(valueAnnotation, "value").get(0); BooleanLiteralAnnotationTerm term = new BooleanLiteralAnnotationTerm(value); return term; } else { CollectionLiteralAnnotationTerm result = new CollectionLiteralAnnotationTerm(BooleanLiteralAnnotationTerm.FACTORY); for (Boolean value : getAnnotationBooleanValues(valueAnnotation, "value")) { result.addElement(new BooleanLiteralAnnotationTerm(value)); } return result; } } private LiteralAnnotationTerm readDeclarationValuesAnnotation( AnnotationMirror valueAnnotation, boolean singleValue) { if (singleValue) { String value = getAnnotationStringValues(valueAnnotation, "value").get(0); DeclarationLiteralAnnotationTerm term = new DeclarationLiteralAnnotationTerm(value); return term; } else { CollectionLiteralAnnotationTerm result = new CollectionLiteralAnnotationTerm(DeclarationLiteralAnnotationTerm.FACTORY); for (String value : getAnnotationStringValues(valueAnnotation, "value")) { result.addElement(new DeclarationLiteralAnnotationTerm(value)); } return result; } } @SuppressWarnings("unchecked") private List getAnnotationClassValues(AnnotationMirror annotation, String field) { return (List)annotation.getValue(field); } @SuppressWarnings("unchecked") private List getAnnotationIntegerValues(AnnotationMirror annotation, String field) { return (List)annotation.getValue(field); } @SuppressWarnings("unchecked") private List getAnnotationBooleanValues(AnnotationMirror annotation, String field) { return (List)annotation.getValue(field); } @SuppressWarnings("unchecked") private List getAnnotationLongValues(AnnotationMirror annotation, String field) { return (List)annotation.getValue(field); } @SuppressWarnings("unchecked") private List getAnnotationDoubleValues(AnnotationMirror annotation, String field) { return (List)annotation.getValue(field); } @SuppressWarnings("unchecked") private List getAnnotationAnnoValues(AnnotationMirror annotation, String field) { return (List)annotation.getValue(field); } @SuppressWarnings("unchecked") private List getAnnotationStringValues(AnnotationMirror annotation, String field) { return (List)annotation.getValue(field); } @SuppressWarnings("unchecked") private List getAnnotationArrayValue(AnnotatedMirror mirror, String type, String field) { return (List) getAnnotationValue(mirror, type, field); } private Object getAnnotationValue(AnnotatedMirror mirror, String type, String fieldName) { AnnotationMirror annotation = mirror.getAnnotation(type); if(annotation != null){ return annotation.getValue(fieldName); } return null; } public void makeInterorAnnotationConstructorInvocation(AnnotationProxyMethod ctor, AnnotationProxyClass klass, java.util.List ctorParams) { AnnotationInvocation ai = new AnnotationInvocation(); ai.setConstructorDeclaration(ctor); ai.setPrimary(klass); ai.setInterop(true); ctor.setAnnotationConstructor(ai); java.util.List annotationArgs = new ArrayList(); for(Parameter ctorParam : ctorParams){ boolean isValue = ctorParam.getName().equals("value"); ParameterAnnotationTerm term = new ParameterAnnotationTerm(); AnnotationArgument argument = new AnnotationArgument(); argument.setTerm(term); argument.setParameter(klass.getParameter(ctorParam.getName())); term.setSourceParameter(ctorParam); AnnotationConstructorParameter acp = new AnnotationConstructorParameter(); acp.setParameter(ctorParam); if(isValue) ai.addConstructorParameter(0, acp); else ai.addConstructorParameter(acp); annotationArgs.add(argument); } ai.getAnnotationArguments().addAll(annotationArgs); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy