通过 GroovyShell 从 java 运行 groovy 时,我遇到了同样的问题。这个解决方案对我有用,解决了 MeiSign 在 tim_yates 解决方案中提到的依赖加载问题。解释如下:
def thisLoader = this.class.classLoader
// try the "proper" way to find the root classloader
def rootLoader = DefaultGroovyMethods.getRootLoader(thisLoader)
if (rootLoader == null) {
// Root classloader is not a groovy RootLoader, but we still need it,
// so walk up the hierarchy and get the top one (whose parent is null)
// When running from Java this is sun.misc.Launcher.ExtClassLoader
rootLoader = thisLoader
ClassLoader parentLoader = rootLoader.getParent()
while (parentLoader != null) {
rootLoader = parentLoader
parentLoader = parentLoader.getParent()
}
}
rootLoader.addURL(new File("gis-geotools-1.9.0.jar").toURL())
def CoordinateTransformer =
Class.forName("de.is24.gis.geotools.CoordinateTransformer",
true,
rootLoader).newInstance();
当使用 groovy.lang.GroovyShell.main 从 java 运行 groovy 时,this.classLoader 是 GroovyClassLoader.InnerLoader 从命令行 groovy.bat 运行 groovy 时,类加载器是org.codehaus.groovy.tools.RootLoader
当您调用时getRootLoader
,它会沿着类加载器层次结构(with-)向上走,getParent()
直到找到一个RootLoade
r 的实例。如果不是,它会发现 null。(这就是NPE
这个问题的标题)
问题是,当从 Java 运行时,层次结构的顶部sun.misc.Launcher.ExtClassLoader
显然根本不是一个 groovy 类,更不用说 groovy RootLoader了。具体来说,层次结构是:
GroovyClassLoader.InnerLoader
--> GroovyClassLoader
---> sun.misc.Launcher.AppClassLoader
----> sun.misc.Launcher.ExtClassLoader
------> null
它是如何以这种方式结束的是非常模糊的GroovyMain
(但如果你真的想自己设置它,那么有一个GroovyShell
带有 ClassLoader 的构造函数)。
无论如何,Tim 的解决方案不能深入工作,因为您正在动态创建的新 ClassLoader 仅用于加载该类而不是后续类。您确实需要将类路径条目添加到根类路径。因此,当 groovy 根失败时,我只是使用了真正的根。
这是来自的原始代码org.codehaus.groovy.runtime.DefaultGroovyMethodsSupport
/**
* Iterates through the classloader parents until it finds a loader with a class
* named "org.codehaus.groovy.tools.RootLoader". If there is no such class
* <code>null</code> will be returned. The name is used for comparison because
* a direct comparison using == may fail as the class may be loaded through
* different classloaders.
*
* @param self a ClassLoader
* @return the rootLoader for the ClassLoader
* @see org.codehaus.groovy.tools.RootLoader
* @since 1.5.0
*/
public static ClassLoader getRootLoader(ClassLoader self) {
while (true) {
if (self == null) return null;
if (isRootLoaderClassOrSubClass(self)) return self;
self = self.getParent();
}
}
private static boolean isRootLoaderClassOrSubClass(ClassLoader self) {
Class current = self.getClass();
while(!current.getName().equals(Object.class.getName())) {
if(current.getName().equals(RootLoader.class.getName())) return true;
current = current.getSuperclass();
}
return false;
}