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

com.redhat.ceylon.model.loader.impl.reflect.ReflectionModelLoader Maven / Gradle / Ivy

There is a newer version: 1.3.3
Show newest version
package com.redhat.ceylon.model.loader.impl.reflect;

import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.List;

import com.redhat.ceylon.common.JVMModuleUtil;
import com.redhat.ceylon.common.Java9ModuleUtil;
import com.redhat.ceylon.common.log.Logger;
import com.redhat.ceylon.model.cmr.JDKUtils;
import com.redhat.ceylon.model.cmr.JDKUtils.JDK;
import com.redhat.ceylon.model.loader.AbstractModelLoader;
import com.redhat.ceylon.model.loader.Timer;
import com.redhat.ceylon.model.loader.TypeParser;
import com.redhat.ceylon.model.loader.impl.reflect.mirror.ReflectionClass;
import com.redhat.ceylon.model.loader.impl.reflect.mirror.ReflectionMethod;
import com.redhat.ceylon.model.loader.mirror.ClassMirror;
import com.redhat.ceylon.model.loader.mirror.MethodMirror;
import com.redhat.ceylon.model.typechecker.model.Module;
import com.redhat.ceylon.model.typechecker.model.Modules;
import com.redhat.ceylon.model.typechecker.model.Unit;
import com.redhat.ceylon.model.typechecker.util.ModuleManager;

/**
 * A model loader which uses Java reflection.
 *
 * @author Stéphane Épardaud 
 */
public abstract class ReflectionModelLoader extends AbstractModelLoader {
	protected Logger log;
	
	static {
	    try{
	        if(JDKUtils.jdk.providesVersion(JDK.JDK9.version)){
	            Object mod = Java9ModuleUtil.getModule(ReflectionModelLoader.class);
	            
	            // make sure we're running as a module, not from the classpath
	            if(Java9ModuleUtil.isNamedModule(mod)){
	                // add a read to the language module since that's where the metadata annotations are
	                Object otherModule = Java9ModuleUtil.findModule(mod, Module.LANGUAGE_MODULE_NAME);
	                if(otherModule != null){
	                    Class moduleClass = ClassLoader.getSystemClassLoader().loadClass("java.lang.reflect.Module");
	                    // also add a read to it
	                    Method addReads = moduleClass.getMethod("addReads", moduleClass);
	                    addReads.invoke(mod, otherModule);
	                }
	            }
	        }
	    }catch(Throwable t){
	        throw new RuntimeException("Failed to add read from model to language module in Java 9", t);
	    }
	}
	
    public ReflectionModelLoader(ModuleManager moduleManager, Modules modules, Logger log){
        initModuleManager(moduleManager);
        this.modules = modules;
        this.typeFactory = new Unit();
        this.typeParser = new TypeParser(this);
        this.timer = new Timer(false);
        this.log = log;
    }

    protected abstract List getPackageList(Module module, String packageName);
    protected abstract boolean packageExists(Module module, String packageName);
    protected abstract Class loadClass(Module module, String name);

    @Override
    public void loadStandardModules() {
        super.loadStandardModules();
        // load two packages for the language module
        Module languageModule = modules.getLanguageModule();
        findOrCreatePackage(languageModule, AbstractModelLoader.CEYLON_LANGUAGE);
        findOrCreatePackage(languageModule, AbstractModelLoader.CEYLON_LANGUAGE_MODEL);
        findOrCreatePackage(languageModule, AbstractModelLoader.CEYLON_LANGUAGE_MODEL_DECLARATION);
        findOrCreatePackage(languageModule, AbstractModelLoader.CEYLON_LANGUAGE_SERIALIZATION);
    }
    
    @Override
    public boolean loadPackage(Module module, String packageName, boolean loadDeclarations) {
        // abort if we already loaded it, but only record that we loaded it if we want
        // to load the declarations, because merely calling complete() on the package
        // is OK
        packageName = JVMModuleUtil.quoteJavaKeywords(packageName);
        if(loadDeclarations && !loadedPackages.add(cacheKeyByModule(module, packageName))){
            return true;
        }
        if(!packageExists(module, packageName))
            return false;
        if(loadDeclarations){
            for(String file : getPackageList(module, packageName)){
                // ignore non-class stuff
                if(!file.toLowerCase().endsWith(".class"))
                    continue;
                // turn it into a class name
                // FIXME: this is terrible
                String className = file.substring(0, file.length()-6).replace('/', '.');
                // get the last part
                int lastDot = className.lastIndexOf('.');
                String lastPart = lastDot == -1 ? className : className.substring(lastDot+1);
                int dollar = lastPart.indexOf('$');
                // if we have a dollar after the first char (where it would be quoting), skip it
                // because those are local/member/anonymous/impl ones
                if(dollar > 0)
                    continue;
                // skip module/package declarations too (do not strip before checking)
                if(isModuleOrPackageDescriptorName(lastPart))
                    continue;

                // the logic for lower-cased names should be abstracted somewhere sane
                if(!isLoadedFromSource(className) 
                        && (!className.endsWith("_") || !isLoadedFromSource(className.substring(0, className.length()-1)))
                        && !isTypeHidden(module, className))
                    convertToDeclaration(module, className, DeclarationType.TYPE);
            }
            if(module.getNameAsString().equals(JAVA_BASE_MODULE_NAME)
                    && packageName.equals("java.lang"))
                loadJavaBaseArrays();
        }
        return true;
    }

    protected boolean isLoadedFromSource(String className) {
        return false;
    }

    @Override
    public ClassMirror lookupNewClassMirror(Module module, String name) {
        Class klass = null;
        // first try with the same name, for Java interop with classes with lowercase name
        klass = loadClass(module, JVMModuleUtil.quoteJavaKeywords(name));
        if (klass == null && lastPartHasLowerInitial(name) && !name.endsWith("_")) {
            klass = loadClass(module, JVMModuleUtil.quoteJavaKeywords(name+"_"));
        }
        return klass != null ? new ReflectionClass(klass) : null;
    }

    @Override
    protected String assembleJavaClass(String javaClass, String packageName) {
        // strip the java class name of its package part
        if(!packageName.isEmpty())
            javaClass = javaClass.substring(packageName.length()+1); // pkg + dot
        // now replace every dot in the name part with $
        javaClass = javaClass.replace('.', '$');
        // assemble back
        if(packageName.isEmpty())
            return javaClass;
        return packageName + "." + javaClass;
    }
    
    @Override
    protected boolean isOverridingMethod(MethodMirror methodSymbol) {
        final Member method = ((ReflectionMethod)methodSymbol).method;
        if (method.getDeclaringClass().getName().contentEquals("ceylon.language.Identifiable")) {
            if (method.getName().contentEquals("equals") || method.getName().contentEquals("hashCode")) {
                return true;
            }
        }
        if (method.getDeclaringClass().getName().contentEquals("ceylon.language.Object")) {
            if (method.getName().contentEquals("equals") || method.getName().contentEquals("hashCode") || method.getName().contentEquals("toString")) {
                return false;
            }
        }
        return ((ReflectionMethod)methodSymbol).isOverridingMethod();
    }
    
    @Override
    protected boolean isOverloadingMethod(MethodMirror methodSymbol) {
        return ((ReflectionMethod)methodSymbol).isOverloadingMethod();
    }

    @Override
    protected void logError(String message) {
        log.error(message);
    }
    
    @Override
    protected void logWarning(String message) {
        log.warning(message);
    }
    
    @Override
    protected void logVerbose(String message) {
        log.debug(message);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy