📄 groovyclassloader.java
字号:
/* * $Id: GroovyClassLoader.java,v 1.76 2006/06/23 15:25:19 blackdrag Exp $ * * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved. * * Redistribution and use of this software and associated documentation * ("Software"), with or without modification, are permitted provided that the * following conditions are met: * 1. Redistributions of source code must retain copyright statements and * notices. Redistributions must also contain a copy of this document. * 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 "groovy" must not be used to endorse or promote products * derived from this Software without prior written permission of The Codehaus. * For written permission, please contact info@codehaus.org. * 4. Products derived from this Software may not be called "groovy" nor may * "groovy" appear in their names without prior written permission of The * Codehaus. "groovy" is a registered trademark of The Codehaus. * 5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/ * * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESSED 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 CODEHAUS OR ITS CONTRIBUTORS 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. * *//** * @TODO: multi threaded compiling of the same class but with different roots * for compilation... T1 compiles A, which uses B, T2 compiles B... mark A and B * as parsed and then synchronize compilation. Problems: How to synchronize? * How to get error messages? * */package groovy.lang;import java.io.ByteArrayInputStream;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.lang.reflect.Field;import java.net.MalformedURLException;import java.net.URL;import java.net.URLClassLoader;import java.security.AccessController;import java.security.CodeSource;import java.security.PrivilegedAction;import java.security.ProtectionDomain;import java.util.ArrayList;import java.util.Collection;import java.util.Enumeration;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import org.codehaus.groovy.ast.ClassNode;import org.codehaus.groovy.ast.ModuleNode;import org.codehaus.groovy.classgen.Verifier;import org.codehaus.groovy.control.CompilationFailedException;import org.codehaus.groovy.control.CompilationUnit;import org.codehaus.groovy.control.CompilerConfiguration;import org.codehaus.groovy.control.Phases;import org.codehaus.groovy.control.SourceUnit;import org.objectweb.asm.ClassVisitor;import org.objectweb.asm.ClassWriter;/** * A ClassLoader which can load Groovy classes. The loaded classes are cached, * classes from other classlaoders should not be cached. To be able to load a * script that was asked for earlier but was created later it is essential not * to keep anything like a "class not found" information for that class name. * This includes possible parent loaders. Classes that are not chached are always * reloaded. * * @author <a href="mailto:james@coredevelopers.net">James Strachan</a> * @author Guillaume Laforge * @author Steve Goetze * @author Bing Ran * @author <a href="mailto:scottstirling@rcn.com">Scott Stirling</a> * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a> * @version $Revision: 1.76 $ */public class GroovyClassLoader extends URLClassLoader { /** * this cache contains the loaded classes or PARSING, if the class is currently parsed */ protected Map classCache = new HashMap(); protected Map sourceCache = new HashMap(); private CompilerConfiguration config; private Boolean recompile = null; // use 1000000 as offset to avoid conflicts with names form the GroovyShell private static int scriptNameCounter = 1000000; private GroovyResourceLoader resourceLoader = new GroovyResourceLoader() { public URL loadGroovySource(final String filename) throws MalformedURLException { URL file = (URL) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { return getSourceFile(filename); } }); return file; } }; /** * creates a GroovyClassLoader using the current Thread's context * Class loader as parent. */ public GroovyClassLoader() { this(Thread.currentThread().getContextClassLoader()); } /** * creates a GroovyClassLoader using the given ClassLoader as parent */ public GroovyClassLoader(ClassLoader loader) { this(loader, null); } /** * creates a GroovyClassLoader using the given GroovyClassLoader as parent. * This loader will get the parent's CompilerConfiguration */ public GroovyClassLoader(GroovyClassLoader parent) { this(parent, parent.config, false); } /** * creates a GroovyClassLaoder. * @param parent the parten class loader * @param config the compiler configuration * @param useConfigurationClasspath determines if the configurations classpath should be added */ public GroovyClassLoader(ClassLoader parent, CompilerConfiguration config, boolean useConfigurationClasspath) { super(new URL[0],parent); if (config==null) config = CompilerConfiguration.DEFAULT; this.config = config; if (useConfigurationClasspath) { for (Iterator it=config.getClasspath().iterator(); it.hasNext();) { String path = (String) it.next(); this.addClasspath(path); } } } /** * creates a GroovyClassLoader using the given ClassLoader as parent. */ public GroovyClassLoader(ClassLoader loader, CompilerConfiguration config) { this(loader,config,true); } public void setResourceLoader(GroovyResourceLoader resourceLoader) { if (resourceLoader == null) { throw new IllegalArgumentException("Resource loader must not be null!"); } this.resourceLoader = resourceLoader; } public GroovyResourceLoader getResourceLoader() { return resourceLoader; } /** * Loads the given class node returning the implementation Class * * @param classNode * @return a class */ public Class defineClass(ClassNode classNode, String file) { //return defineClass(classNode, file, "/groovy/defineClass"); throw new DeprecationException("the method GroovyClassLoader#defineClass(ClassNode, String) is no longer used and removed"); } /** * Loads the given class node returning the implementation Class. * * WARNING: this compilation is not synchronized * * @param classNode * @return a class */ public Class defineClass(ClassNode classNode, String file, String newCodeBase) { CodeSource codeSource = null; try { codeSource = new CodeSource(new URL("file", "", newCodeBase), (java.security.cert.Certificate[]) null); } catch (MalformedURLException e) { //swallow } CompilationUnit unit = createCompilationUnit(config,codeSource); ClassCollector collector = createCollector(unit,classNode.getModule().getContext()); try { unit.addClassNode(classNode); unit.setClassgenCallback(collector); unit.compile(Phases.CLASS_GENERATION); return collector.generatedClass; } catch (CompilationFailedException e) { throw new RuntimeException(e); } } /** * Parses the given file into a Java class capable of being run * * @param file the file name to parse * @return the main class defined in the given script */ public Class parseClass(File file) throws CompilationFailedException, IOException { return parseClass(new GroovyCodeSource(file)); } /** * Parses the given text into a Java class capable of being run * * @param text the text of the script/class to parse * @param fileName the file name to use as the name of the class * @return the main class defined in the given script */ public Class parseClass(String text, String fileName) throws CompilationFailedException { return parseClass(new ByteArrayInputStream(text.getBytes()), fileName); } /** * Parses the given text into a Java class capable of being run * * @param text the text of the script/class to parse * @return the main class defined in the given script */ public Class parseClass(String text) throws CompilationFailedException { return parseClass(new ByteArrayInputStream(text.getBytes()), "script" + System.currentTimeMillis() + ".groovy"); } /** * Parses the given character stream into a Java class capable of being run * * @param in an InputStream * @return the main class defined in the given script */ public Class parseClass(InputStream in) throws CompilationFailedException { return parseClass(in, generateScriptName()); } public synchronized String generateScriptName() { scriptNameCounter++; return "script"+scriptNameCounter+".groovy"; } public Class parseClass(final InputStream in, final String fileName) throws CompilationFailedException { // For generic input streams, provide a catch-all codebase of // GroovyScript // Security for these classes can be administered via policy grants with // a codebase of file:groovy.script GroovyCodeSource gcs = (GroovyCodeSource) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { return new GroovyCodeSource(in, fileName, "/groovy/script"); } }); return parseClass(gcs); } public Class parseClass(GroovyCodeSource codeSource) throws CompilationFailedException { return parseClass(codeSource, codeSource.isCachable()); } /** * Parses the given code source into a Java class. If there is a class file * for the given code source, then no parsing is done, instead the cached class is returned. * * @param shouldCacheSource if true then the generated class will be stored in the source cache *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -