📄 groovyclassloader.java
字号:
* @return true if the class should be compiled again */ protected boolean isRecompilable(Class cls) { if (cls==null) return true; if (recompile==null && !config.getRecompileGroovySource()) return false; if (recompile!=null && !recompile.booleanValue()) return false; if (!GroovyObject.class.isAssignableFrom(cls)) return false; long timestamp = getTimeStamp(cls); if (timestamp == Long.MAX_VALUE) return false; return true; } /** * sets if the recompilation should be enable. There are 3 possible * values for this. Any value different than null overrides the * value from the compiler configuration. true means to recompile if needed * false means to never recompile. * @param mode the recompilation mode * @see CompilerConfiguration */ public void setShouldRecompile(Boolean mode){ recompile = mode; } /** * gets the currently set recompilation mode. null means, the * compiler configuration is used. False means no recompilation and * true means that recompilation will be done if needed. * @return the recompilation mode */ public Boolean isShouldRecompile(){ return recompile; } /** * loads a class from a file or a parent classloader. * * @param name of the class to be loaded * @param lookupScriptFiles if false no lookup at files is done at all * @param preferClassOverScript if true the file lookup is only done if there is no class * @param resolve @see ClassLoader#loadClass(java.lang.String, boolean) * @return the class found or the class created from a file lookup * @throws ClassNotFoundException */ public Class loadClass(final String name, boolean lookupScriptFiles, boolean preferClassOverScript, boolean resolve) throws ClassNotFoundException, CompilationFailedException { // look into cache Class cls=getClassCacheEntry(name); // enable recompilation? boolean recompile = isRecompilable(cls); if (!recompile) return cls; // check security manager SecurityManager sm = System.getSecurityManager(); if (sm != null) { String className = name.replace('/', '.'); int i = className.lastIndexOf('.'); if (i != -1) { sm.checkPackageAccess(className.substring(0, i)); } } // try parent loader ClassNotFoundException last = null; try { Class parentClassLoaderClass = super.loadClass(name, resolve); // always return if the parent loader was successfull if (cls!=parentClassLoaderClass) return parentClassLoaderClass; } catch (ClassNotFoundException cnfe) { last = cnfe; } catch (NoClassDefFoundError ncdfe) { if (ncdfe.getMessage().indexOf("wrong name")>0) { last = new ClassNotFoundException(name); } else { throw ncdfe; } } if (cls!=null) { // prefer class if no recompilation preferClassOverScript |= !recompile; if (preferClassOverScript) return cls; } // at this point the loading from a parent loader failed // and we want to recompile if needed. if (lookupScriptFiles) { // synchronize on cache, as we want only one compilation // at the same time synchronized (classCache) { // try groovy file try { // check if recompilation already happend. if (getClassCacheEntry(name)!=cls) return getClassCacheEntry(name); URL source = resourceLoader.loadGroovySource(name); cls = recompile(source,name,cls); } catch (IOException ioe) { last = new ClassNotFoundException("IOException while openening groovy source: " + name, ioe); } finally { if (cls==null) { removeClassCacheEntry(name); } else { setClassCacheEntry(cls); } } } } if (cls==null) { // no class found, there has to be an exception before then if (last==null) throw new AssertionError(true); throw last; } return cls; } /** * (Re)Comipiles the given source. * This method starts the compilation of a given source, if * the source has changed since the class was created. For * this isSourceNewer is called. * * @see #isSourceNewer(URL, Class) * @param source the source pointer for the compilation * @param className the name of the class to be generated * @param oldClass a possible former class * @return the old class if the source wasn't new enough, the new class else * @throws CompilationFailedException if the compilation failed * @throws IOException if the source is not readable * */ protected Class recompile(URL source, String className, Class oldClass) throws CompilationFailedException, IOException { if (source != null) { // found a source, compile it if newer if ((oldClass!=null && isSourceNewer(source, oldClass)) || (oldClass==null)) { sourceCache.remove(className); return parseClass(source.openStream(),className); } } return oldClass; } /** * Implemented here to check package access prior to returning an * already loaded class. * @throws CompilationFailedException if the compilation failed * @throws ClassNotFoundException if the class was not found * @see java.lang.ClassLoader#loadClass(java.lang.String, boolean) */ protected Class loadClass(final String name, boolean resolve) throws ClassNotFoundException { return loadClass(name,true,false,resolve); } /** * gets the time stamp of a given class. For groovy * generated classes this usually means to return the value * of the static field __timeStamp. If the parameter doesn't * have such a field, then Long.MAX_VALUE is returned * * @param cls the class * @return the time stamp */ protected long getTimeStamp(Class cls) { Long o; try { Field field = cls.getField(Verifier.__TIMESTAMP); o = (Long) field.get(null); } catch (Exception e) { return Long.MAX_VALUE; } return o.longValue(); } private URL getSourceFile(String name) { String filename = name.replace('.', '/') + config.getDefaultScriptExtension(); URL ret = getResource(filename); if (ret!=null && ret.getProtocol().equals("file")) { String fileWithoutPackage = filename; if (fileWithoutPackage.indexOf('/')!=-1){ int index = fileWithoutPackage.lastIndexOf('/'); fileWithoutPackage = fileWithoutPackage.substring(index+1); } File path = new File(ret.getFile()).getParentFile(); if (path.exists() && path.isDirectory()) { File file = new File(path, fileWithoutPackage); if (file.exists()) { // file.exists() might be case insensitive. Let's do // case sensitive match for the filename File parent = file.getParentFile(); String[] files = parent.list(); for (int j = 0; j < files.length; j++) { if (files[j].equals(fileWithoutPackage)) return ret; } } } //file does not exist! return null; } return ret; } /** * Decides if the given source is newer than a class. * * @see #getTimeStamp(Class) * @param source the source we may want to compile * @param cls the former class * @return true if the source is newer, false else * @throws IOException if it is not possible to open an * connection for the given source */ protected boolean isSourceNewer(URL source, Class cls) throws IOException { long lastMod; // Special handling for file:// protocol, as getLastModified() often reports // incorrect results (-1) if (source.getProtocol().equals("file")) { // Coerce the file URL to a File String path = source.getPath().replace('/', File.separatorChar).replace('|', ':'); File file = new File(path); lastMod = file.lastModified(); } else { lastMod = source.openConnection().getLastModified(); } long classTime = getTimeStamp(cls); return classTime+config.getMinimumRecompilationIntervall() < lastMod; } /** * adds a classpath to this classloader. * @param path is a jar file or a directory. * @see #addURL(URL) */ public void addClasspath(final String path) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { try { File f = new File(path); URL newURL = f.toURI().toURL(); URL[] urls = getURLs(); for (int i=0; i<urls.length; i++) { if (urls[i].equals(newURL)) return null; } addURL(newURL); } catch (MalformedURLException e) { //TODO: fail through ? } return null; } }); } /** * <p>Returns all Groovy classes loaded by this class loader. * * @return all classes loaded by this class loader */ public Class[] getLoadedClasses() { synchronized (classCache) { return (Class[]) classCache.values().toArray(new Class[0]); } } /** * removes all classes from the class cache. * @see #getClassCacheEntry(String) * @see #setClassCacheEntry(Class) * @see #removeClassCacheEntry(String) */ public void clearCache() { synchronized (classCache) { classCache.clear(); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -