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

com.greenpepper.shaded.org.codehaus.janino.IClassLoader Maven / Gradle / Ivy

There is a newer version: 4.2.4
Show newest version

/*
 * Janino - An embedded Java[TM] compiler
 *
 * Copyright (c) 2001-2010, Arno Unkrig
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 * following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
 *       following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 *       following disclaimer in the documentation and/or other materials provided with the distribution.
 *    3. The name of the author may not be used to endorse or promote products derived from this software without
 *       specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package com.greenpepper.shaded.org.codehaus.janino;

import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import com.greenpepper.shaded.org.codehaus.janino.IClass.IConstructor;
import com.greenpepper.shaded.org.codehaus.janino.IClass.IMethod;
import com.greenpepper.shaded.org.codehaus.janino.util.resource.JarDirectoriesResourceFinder;
import com.greenpepper.shaded.org.codehaus.janino.util.resource.PathResourceFinder;
import com.greenpepper.shaded.org.codehaus.janino.util.resource.ResourceFinder;

/** Loads an {@link IClass} by type name. */
@SuppressWarnings({ "rawtypes", "unchecked" }) public abstract
class IClassLoader {
    private static final boolean DEBUG = false;

    // The following are constants, but cannot be declared FINAL, because they are only initialized by
    // "postConstruct()".

    // CHECKSTYLE MemberName:OFF
    // CHECKSTYLE AbbreviationAsWordInName:OFF
    /** Representation of the {@link java.lang.Override} annotation. */
    public IClass ANNO_java_lang_Override;

    /** Representation of the {@link java.lang.AssertionError} type. */
    public IClass TYPE_java_lang_AssertionError;
    /** Representation of the {@link java.lang.Boolean} type. */
    public IClass TYPE_java_lang_Boolean;
    /** Representation of the {@link java.lang.Byte} type. */
    public IClass TYPE_java_lang_Byte;
    /** Representation of the {@link java.lang.Character} type. */
    public IClass TYPE_java_lang_Character;
    /** Representation of the {@link java.lang.Class} type. */
    public IClass TYPE_java_lang_Class;
    /** Representation of the {@link java.lang.Cloneable} type. */
    public IClass TYPE_java_lang_Cloneable;
    /** Representation of the {@link java.lang.Double} type. */
    public IClass TYPE_java_lang_Double;
    /** Representation of the {@link java.lang.Exception} type. */
    public IClass TYPE_java_lang_Exception;
    /** Representation of the {@link java.lang.Error} type. */
    public IClass TYPE_java_lang_Error;
    /** Representation of the {@link java.lang.Float} type. */
    public IClass TYPE_java_lang_Float;
    /** Representation of the {@link java.lang.Integer} type. */
    public IClass TYPE_java_lang_Integer;
    /** Representation of the {@link java.lang.Iterable} type. */
    public IClass TYPE_java_lang_Iterable;
    /** Representation of the {@link java.lang.Long} type. */
    public IClass TYPE_java_lang_Long;
    /** Representation of the {@link java.lang.Object} type. */
    public IClass TYPE_java_lang_Object;
    /** Representation of the {@link java.lang.RuntimeException} type. */
    public IClass TYPE_java_lang_RuntimeException;
    /** Representation of the {@link java.lang.Short} type. */
    public IClass TYPE_java_lang_Short;
    /** Representation of the {@link java.lang.String} type. */
    public IClass TYPE_java_lang_String;
    /** Representation of the {@link java.lang.StringBuilder} type. */
    public IClass TYPE_java_lang_StringBuilder;
    /** Representation of the {@link java.lang.Throwable} type. */
    public IClass TYPE_java_lang_Throwable;
    /** Representation of the {@link java.io.Serializable} type. */
    public IClass TYPE_java_io_Serializable;
    /** Representation of the {@link java.util.Iterator} type. */
    public IClass TYPE_java_util_Iterator;

    /** Representation of the {@link Iterable#iterator()} method. */
    public IMethod METH_java_lang_Iterable__iterator;
    /** Representation of the {@link String#concat(String)} method. */
    public IMethod METH_java_lang_String__concat__java_lang_String;
    /** Representation of the {@link String#valueOf(int)} method. */
    public IMethod METH_java_lang_String__valueOf__int;
    /** Representation of the {@link String#valueOf(long)} method. */
    public IMethod METH_java_lang_String__valueOf__long;
    /** Representation of the {@link String#valueOf(float)} method. */
    public IMethod METH_java_lang_String__valueOf__float;
    /** Representation of the {@link String#valueOf(double)} method. */
    public IMethod METH_java_lang_String__valueOf__double;
    /** Representation of the {@link String#valueOf(char)} method. */
    public IMethod METH_java_lang_String__valueOf__char;
    /** Representation of the {@link String#valueOf(boolean)} method. */
    public IMethod METH_java_lang_String__valueOf__boolean;
    /** Representation of the {@link String#valueOf(Object)} method. */
    public IMethod METH_java_lang_String__valueOf__java_lang_Object;
    /** Representation of the {@link StringBuilder#append(String)} method. */
    public IMethod METH_java_lang_StringBuilder__append__java_lang_String;
    /** Representation of the {@link StringBuilder#toString()} method. */
    public IMethod METH_java_lang_StringBuilder__toString;
    /** Representation of the {@link java.util.Iterator#hasNext()} method. */
    public IMethod METH_java_util_Iterator__hasNext;
    /** Representation of the {@link java.util.Iterator#next()} method. */
    public IMethod METH_java_util_Iterator__next;

    /** Representation of the {@link StringBuilder#StringBuilder(String)} constructor. */
    public IConstructor CTOR_java_lang_StringBuilder__java_lang_String;
    // CHECKSTYLE AbbreviationAsWordInName:ON
    // CHECKSTYLE MemberName:ON

    public
    IClassLoader(IClassLoader optionalParentIClassLoader) {
        this.optionalParentIClassLoader = optionalParentIClassLoader;
    }

    /**
     * This method must be called by the constructor of the directly derived
     * class. (The reason being is that this method invokes abstract
     * {@link #loadIClass(String)} which will not work until the implementing
     * class is constructed.)
     */
    protected final void
    postConstruct() {
        try {
            this.ANNO_java_lang_Override = this.loadIClass(Descriptor.JAVA_LANG_OVERRIDE);

            this.TYPE_java_lang_AssertionError   = this.loadIClass(Descriptor.JAVA_LANG_ASSERTIONERROR);
            this.TYPE_java_lang_Boolean          = this.loadIClass(Descriptor.JAVA_LANG_BOOLEAN);
            this.TYPE_java_lang_Byte             = this.loadIClass(Descriptor.JAVA_LANG_BYTE);
            this.TYPE_java_lang_Character        = this.loadIClass(Descriptor.JAVA_LANG_CHARACTER);
            this.TYPE_java_lang_Class            = this.loadIClass(Descriptor.JAVA_LANG_CLASS);
            this.TYPE_java_lang_Cloneable        = this.loadIClass(Descriptor.JAVA_LANG_CLONEABLE);
            this.TYPE_java_lang_Double           = this.loadIClass(Descriptor.JAVA_LANG_DOUBLE);
            this.TYPE_java_lang_Exception        = this.loadIClass(Descriptor.JAVA_LANG_EXCEPTION);
            this.TYPE_java_lang_Error            = this.loadIClass(Descriptor.JAVA_LANG_ERROR);
            this.TYPE_java_lang_Float            = this.loadIClass(Descriptor.JAVA_LANG_FLOAT);
            this.TYPE_java_lang_Integer          = this.loadIClass(Descriptor.JAVA_LANG_INTEGER);
            this.TYPE_java_lang_Iterable         = this.loadIClass(Descriptor.JAVA_LANG_ITERABLE);
            this.TYPE_java_lang_Long             = this.loadIClass(Descriptor.JAVA_LANG_LONG);
            this.TYPE_java_lang_Object           = this.loadIClass(Descriptor.JAVA_LANG_OBJECT);
            this.TYPE_java_lang_RuntimeException = this.loadIClass(Descriptor.JAVA_LANG_RUNTIMEEXCEPTION);
            this.TYPE_java_lang_Short            = this.loadIClass(Descriptor.JAVA_LANG_SHORT);
            this.TYPE_java_lang_String           = this.loadIClass(Descriptor.JAVA_LANG_STRING);
            this.TYPE_java_lang_StringBuilder    = this.loadIClass(Descriptor.JAVA_LANG_STRINGBUILDER);
            this.TYPE_java_lang_Throwable        = this.loadIClass(Descriptor.JAVA_LANG_THROWABLE);
            this.TYPE_java_io_Serializable       = this.loadIClass(Descriptor.JAVA_IO_SERIALIZABLE);
            this.TYPE_java_util_Iterator         = this.loadIClass(Descriptor.JAVA_UTIL_ITERATOR);

            // CHECKSTYLE LineLength:OFF
            // CHECKSTYLE Whitespace:OFF
            this.METH_java_lang_Iterable__iterator                      = this.TYPE_java_lang_Iterable     .findIMethod("iterator", new IClass[0]);
            this.METH_java_lang_String__concat__java_lang_String        = this.TYPE_java_lang_String       .findIMethod("concat",   new IClass[] { this.TYPE_java_lang_String });
            this.METH_java_lang_String__valueOf__int                    = this.TYPE_java_lang_String       .findIMethod("valueOf",  new IClass[] { IClass.INT });
            this.METH_java_lang_String__valueOf__long                   = this.TYPE_java_lang_String       .findIMethod("valueOf",  new IClass[] { IClass.LONG });
            this.METH_java_lang_String__valueOf__float                  = this.TYPE_java_lang_String       .findIMethod("valueOf",  new IClass[] { IClass.FLOAT });
            this.METH_java_lang_String__valueOf__double                 = this.TYPE_java_lang_String       .findIMethod("valueOf",  new IClass[] { IClass.DOUBLE });
            this.METH_java_lang_String__valueOf__char                   = this.TYPE_java_lang_String       .findIMethod("valueOf",  new IClass[] { IClass.CHAR });
            this.METH_java_lang_String__valueOf__boolean                = this.TYPE_java_lang_String       .findIMethod("valueOf",  new IClass[] { IClass.BOOLEAN });
            this.METH_java_lang_String__valueOf__java_lang_Object       = this.TYPE_java_lang_String       .findIMethod("valueOf",  new IClass[] { this.TYPE_java_lang_Object });
            this.METH_java_lang_StringBuilder__append__java_lang_String = this.TYPE_java_lang_StringBuilder.findIMethod("append",   new IClass[] { this.TYPE_java_lang_String });
            this.METH_java_lang_StringBuilder__toString                 = this.TYPE_java_lang_StringBuilder.findIMethod("toString", new IClass[0]);
            this.METH_java_util_Iterator__hasNext                       = this.TYPE_java_util_Iterator     .findIMethod("hasNext",  new IClass[0]);
            this.METH_java_util_Iterator__next                          = this.TYPE_java_util_Iterator     .findIMethod("next",     new IClass[0]);

            this.CTOR_java_lang_StringBuilder__java_lang_String   = this.TYPE_java_lang_StringBuilder.findIConstructor(new IClass[] { this.TYPE_java_lang_String });
            // CHECKSTYLE Whitespace:ON
            // CHECKSTYLE LineLength:ON
        } catch (Exception e) {
            throw new JaninoRuntimeException("Cannot load simple types", e);
        }
    }

    /**
     * Get an {@link IClass} by field descriptor.
     *
     * @param fieldDescriptor         E.g. 'Lpkg1/pkg2/Outer$Inner;'
     * @return                        {@code null} if an {@link IClass} could not be loaded
     * @throws ClassNotFoundException An exception was raised while loading the {@link IClass}
     */
    public final IClass
    loadIClass(String fieldDescriptor) throws ClassNotFoundException {
        if (IClassLoader.DEBUG) System.out.println(this + ": Load type \"" + fieldDescriptor + "\"");

        if (Descriptor.isPrimitive(fieldDescriptor)) {
            return (
                fieldDescriptor.equals(Descriptor.VOID)    ? IClass.VOID :
                fieldDescriptor.equals(Descriptor.BYTE)    ? IClass.BYTE :
                fieldDescriptor.equals(Descriptor.CHAR)    ? IClass.CHAR :
                fieldDescriptor.equals(Descriptor.DOUBLE)  ? IClass.DOUBLE :
                fieldDescriptor.equals(Descriptor.FLOAT)   ? IClass.FLOAT :
                fieldDescriptor.equals(Descriptor.INT)     ? IClass.INT :
                fieldDescriptor.equals(Descriptor.LONG)    ? IClass.LONG :
                fieldDescriptor.equals(Descriptor.SHORT)   ? IClass.SHORT :
                fieldDescriptor.equals(Descriptor.BOOLEAN) ? IClass.BOOLEAN :
                null
            );
        }

        // Ask parent IClassLoader first.
        if (this.optionalParentIClassLoader != null) {
            IClass res = this.optionalParentIClassLoader.loadIClass(fieldDescriptor);
            if (res != null) return res;
        }

        // We need to synchronize here because "unloadableIClasses" and
        // "loadedIClasses" are unsynchronized containers.
        IClass result;
        synchronized (this) {

            // Class could not be loaded before?
            if (this.unloadableIClasses.contains(fieldDescriptor)) return null;

            // Class already loaded?
            result = (IClass) this.loadedIClasses.get(fieldDescriptor);
            if (result != null) return result;

            // Special handling for array types.
            if (Descriptor.isArrayReference(fieldDescriptor)) {

                // Load the component type.
                IClass componentIClass = this.loadIClass(
                    Descriptor.getComponentDescriptor(fieldDescriptor)
                );
                if (componentIClass == null) return null;

                // Now get and define the array type.
                IClass arrayIClass = componentIClass.getArrayIClass(this.TYPE_java_lang_Object);
                this.loadedIClasses.put(fieldDescriptor, arrayIClass);
                return arrayIClass;
            }

            if (IClassLoader.DEBUG) System.out.println("call IClassLoader.findIClass(\"" + fieldDescriptor + "\")");

            // Load the class through the {@link #findIClass(String)} method implemented by the
            // derived class.
            result = this.findIClass(fieldDescriptor);
            if (result == null) {
                this.unloadableIClasses.add(fieldDescriptor);
                return null;
            }
        }

        if (!result.getDescriptor().equalsIgnoreCase(fieldDescriptor)) {
            throw new JaninoRuntimeException(
                "\"findIClass()\" returned \""
                + result.getDescriptor()
                + "\" instead of \""
                + fieldDescriptor
                + "\""
            );
        }

        if (IClassLoader.DEBUG) System.out.println(this + ": Loaded type \"" + fieldDescriptor + "\" as " + result);

        return result;
    }

    /**
     * Find a new {@link IClass} by descriptor; return null if a class
     * for that descriptor could not be found.
     * 

* Similar {@link java.lang.ClassLoader#findClass(java.lang.String)}, this method * must *

    *
  • Get an {@link IClass} object from somewhere for the given type *
  • Call {@link #defineIClass(IClass)} with that {@link IClass} object as * the argument *
  • Return the {@link IClass} object *
*

* The format of a descriptor is defined in JVMS 4.3.2. Typical * descriptors are: *

    *
  • I (Integer) *
  • Lpkg1/pkg2/Cls; (Class declared in package) *
  • Lpkg1/pkg2/Outer$Inner; Member class *
* Notice that this method is never called for array types. *

* Notice that this method is never called from more than one thread at a time. * In other words, implementations of this method need not be synchronized. * * @return null if a class with that descriptor could not be found * @throws ClassNotFoundException if an exception was raised while loading the class */ protected abstract IClass findIClass(String descriptor) throws ClassNotFoundException; /** * Define an {@link IClass} in the context of this {@link IClassLoader}. * If an {@link IClass} with that descriptor already exists, a * {@link RuntimeException} is thrown. *

* This method should only be called from an implementation of * {@link #findIClass(String)}. * * @throws RuntimeException A different {@link IClass} object is already defined for this type */ protected final void defineIClass(IClass iClass) { String descriptor = iClass.getDescriptor(); // Already defined? IClass loadedIClass = (IClass) this.loadedIClasses.get(descriptor); if (loadedIClass != null) { if (loadedIClass == iClass) return; throw new JaninoRuntimeException("Non-identical definition of IClass \"" + descriptor + "\""); } // Define. this.loadedIClasses.put(descriptor, iClass); if (IClassLoader.DEBUG) System.out.println(this + ": Defined type \"" + descriptor + "\""); } /** * Create an {@link IClassLoader} that looks for classes in the given "boot class * path", then in the given "extension directories", and then in the given * "class path". *

* The default for the optionalBootClassPath is the path defined in * the system property "sun.boot.class.path", and the default for the * optionalExtensionDirs is the path defined in the "java.ext.dirs" * system property. */ public static IClassLoader createJavacLikePathIClassLoader( final File[] optionalBootClassPath, final File[] optionalExtDirs, final File[] classPath ) { ResourceFinder bootClassPathResourceFinder = new PathResourceFinder( optionalBootClassPath == null ? PathResourceFinder.parsePath(System.getProperty("sun.boot.class.path")) : optionalBootClassPath ); ResourceFinder extensionDirectoriesResourceFinder = new JarDirectoriesResourceFinder( optionalExtDirs == null ? PathResourceFinder.parsePath(System.getProperty("java.ext.dirs")) : optionalExtDirs ); final ResourceFinder classPathResourceFinder = new PathResourceFinder(classPath); // We can load classes through "ResourceFinderIClassLoader"s, which means // they are read into "ClassFile" objects, or we can load classes through // "ClassLoaderIClassLoader"s, which means they are loaded into the JVM. // // In my environment, the latter is slightly faster. No figures about // resource usage yet. // // In applications where the generated classes are not loaded into the // same JVM instance, we should avoid to use the // ClassLoaderIClassLoader, because that assumes that final fields have // a constant value, even if not compile-time-constant but only // initialization-time constant. The classical example is // "File.separator", which is non-blank final, but not compile-time- // constant. IClassLoader icl; icl = new ResourceFinderIClassLoader(bootClassPathResourceFinder, null); icl = new ResourceFinderIClassLoader(extensionDirectoriesResourceFinder, icl); icl = new ResourceFinderIClassLoader(classPathResourceFinder, icl); return icl; } private final IClassLoader optionalParentIClassLoader; private final Map loadedIClasses = new HashMap(); private final Set unloadableIClasses = new HashSet(); }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy