📄 groovyclassloader.java
字号:
* @return the main class defined in the given script */ public Class parseClass(GroovyCodeSource codeSource, boolean shouldCacheSource) throws CompilationFailedException { synchronized (classCache) { Class answer = (Class) sourceCache.get(codeSource.getName()); if (answer!=null) return answer; // Was neither already loaded nor compiling, so compile and add to // cache. try { CompilationUnit unit = createCompilationUnit(config, codeSource.getCodeSource()); SourceUnit su = null; if (codeSource.getFile()==null) { su = unit.addSource(codeSource.getName(), codeSource.getInputStream()); } else { su = unit.addSource(codeSource.getFile()); } ClassCollector collector = createCollector(unit,su); unit.setClassgenCallback(collector); int goalPhase = Phases.CLASS_GENERATION; if (config != null && config.getTargetDirectory()!=null) goalPhase = Phases.OUTPUT; unit.compile(goalPhase); answer = collector.generatedClass; for (Iterator iter = collector.getLoadedClasses().iterator(); iter.hasNext();) { Class clazz = (Class) iter.next(); setClassCacheEntry(clazz); } if (shouldCacheSource) sourceCache.put(codeSource.getName(), answer); } finally { try { codeSource.getInputStream().close(); } catch (IOException e) { throw new GroovyRuntimeException("unable to close stream",e); } } return answer; } } /** * gets the currently used classpath. * @return a String[] containing the file information of the urls * @see #getURLs() */ protected String[] getClassPath() { //workaround for Groovy-835 URL[] urls = getURLs(); String[] ret = new String[urls.length]; for (int i = 0; i < ret.length; i++) { ret[i] = urls[i].getFile(); } return ret; } /** * expands the classpath * @param pathList an empty list that will contain the elements of the classpath * @param classpath the classpath specified as a single string * @deprecated */ protected void expandClassPath(List pathList, String base, String classpath, boolean isManifestClasspath) { throw new DeprecationException("the method groovy.lang.GroovyClassLoader#expandClassPath(List,String,String,boolean) is no longer used internally and removed"); } /** * A helper method to allow bytecode to be loaded. spg changed name to * defineClass to make it more consistent with other ClassLoader methods * @deprecated */ protected Class defineClass(String name, byte[] bytecode, ProtectionDomain domain) { throw new DeprecationException("the method groovy.lang.GroovyClassLoader#defineClass(String,byte[],ProtectionDomain) is no longer used internally and removed"); } public static class InnerLoader extends GroovyClassLoader{ private GroovyClassLoader delegate; public InnerLoader(GroovyClassLoader delegate) { super(delegate); this.delegate = delegate; } public void addClasspath(String path) { delegate.addClasspath(path); } public void clearCache() { delegate.clearCache(); } public URL findResource(String name) { return delegate.findResource(name); } public Enumeration findResources(String name) throws IOException { return delegate.findResources(name); } public Class[] getLoadedClasses() { return delegate.getLoadedClasses(); } public URL getResource(String name) { return delegate.getResource(name); } public InputStream getResourceAsStream(String name) { return delegate.getResourceAsStream(name); } public GroovyResourceLoader getResourceLoader() { return delegate.getResourceLoader(); } public URL[] getURLs() { return delegate.getURLs(); } public Class loadClass(String name, boolean lookupScriptFiles, boolean preferClassOverScript, boolean resolve) throws ClassNotFoundException, CompilationFailedException { Class c = findLoadedClass(name); if (c!=null) return c; return delegate.loadClass(name, lookupScriptFiles, preferClassOverScript, resolve); } public Class parseClass(GroovyCodeSource codeSource, boolean shouldCache) throws CompilationFailedException { return delegate.parseClass(codeSource, shouldCache); } public void setResourceLoader(GroovyResourceLoader resourceLoader) { delegate.setResourceLoader(resourceLoader); } public void addURL(URL url) { delegate.addURL(url); } } /** * creates a new CompilationUnit. If you want to add additional * phase operations to the CompilationUnit (for example to inject * additional methods, variables, fields), then you should overwrite * this method. * * @param config the compiler configuration, usually the same as for this class loader * @param source the source containing the initial file to compile, more files may follow during compilation * * @return the CompilationUnit */ protected CompilationUnit createCompilationUnit(CompilerConfiguration config, CodeSource source) { return new CompilationUnit(config, source, this); } /** * creates a ClassCollector for a new compilation. * @param unit the compilationUnit * @param su the SoruceUnit * @return the ClassCollector */ protected ClassCollector createCollector(CompilationUnit unit,SourceUnit su) { InnerLoader loader = (InnerLoader) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { return new InnerLoader(GroovyClassLoader.this); } }); return new ClassCollector(loader, unit, su); } public static class ClassCollector extends CompilationUnit.ClassgenCallback { private Class generatedClass; private GroovyClassLoader cl; private SourceUnit su; private CompilationUnit unit; private Collection loadedClasses = null; protected ClassCollector(InnerLoader cl, CompilationUnit unit, SourceUnit su) { this.cl = cl; this.unit = unit; this.loadedClasses = new ArrayList(); this.su = su; } protected Class onClassNode(ClassWriter classWriter, ClassNode classNode) { byte[] code = classWriter.toByteArray(); Class theClass = cl.defineClass(classNode.getName(), code, 0, code.length, unit.getAST().getCodeSource()); cl.resolveClass(theClass); this.loadedClasses.add(theClass); if (generatedClass == null) { ModuleNode mn = classNode.getModule(); SourceUnit msu = null; if (mn!=null) msu = mn.getContext(); ClassNode main = null; if (mn!=null) main = (ClassNode) mn.getClasses().get(0); if (msu==su && main==classNode) generatedClass = theClass; } return theClass; } public void call(ClassVisitor classWriter, ClassNode classNode) { onClassNode((ClassWriter) classWriter, classNode); } public Collection getLoadedClasses() { return this.loadedClasses; } } /** * open up the super class define that takes raw bytes * */ public Class defineClass(String name, byte[] b) { return super.defineClass(name, b, 0, b.length); } /** * loads a class from a file or a parent classloader. * This method does call loadClass(String, boolean, boolean, boolean) * with the last parameter set to false. * @throws CompilationFailedException */ public Class loadClass(final String name, boolean lookupScriptFiles, boolean preferClassOverScript) throws ClassNotFoundException, CompilationFailedException { return loadClass(name,lookupScriptFiles,preferClassOverScript,false); } /** * gets a class from the class cache. This cache contains only classes loaded through * this class loader or an InnerLoader instance. If no class is stored for a * specific name, then the method should return null. * * @param name of the class * @return the class stored for the given name * @see #removeClassCacheEntry(String) * @see #setClassCacheEntry(Class) * @see #clearCache() */ protected Class getClassCacheEntry(String name) { if (name==null) return null; synchronized (classCache) { Class cls = (Class) classCache.get(name); return cls; } } /** * sets an entry in the class cache. * @param cls the class * @see #removeClassCacheEntry(String) * @see #getClassCacheEntry(String) * @see #clearCache() */ protected void setClassCacheEntry(Class cls) { synchronized (classCache) { classCache.put(cls.getName(),cls); } } /** * removes a class from the class cache. * @param name of the class * @see #getClassCacheEntry(String) * @see #setClassCacheEntry(Class) * @see #clearCache() */ protected void removeClassCacheEntry(String name) { synchronized (classCache) { classCache.remove(name); } } /** * adds a URL to the classloader. * @param url the new classpath element */ public void addURL(URL url) { super.addURL(url); } /** * Indicates if a class is recompilable. Recompileable means, that the classloader * will try to locate a groovy source file for this class and then compile it again, * adding the resulting class as entry to the cache. Giving null as class is like a * recompilation, so the method should always return true here. Only classes that are * implementing GroovyObject are compileable and only if the timestamp in the class * is lower than Long.MAX_VALUE. * * NOTE: First the parent loaders will be asked and only if they don't return a * class the recompilation will happen. Recompilation also only happen if the source * file is newer. * * @see #isSourceNewer(URL, Class) * @param cls the class to be tested. If null the method should return true
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -