0

我创建了以下 Groovy 脚本来使用 Java 库转换 JSON 文档。但不知何故,我无法从我需要的 jar 中加载类。我总是得到java.lang.ClassNotFoundException: de.is24.gis.geotools.CoordinateTransformer

Jar 文件与 groovy 脚本位于同一目录中。我无法编辑调用 groovy 脚本的方式。它被河流自动调用。

import groovy.json.JsonSlurper

geo = new GeoTransformer()
geo.transform(ctx.document)

class GeoTransformer {
    void transform(doc) {
        this.getClass().classLoader.addURL(new File("gis-geotools-1.9.0.jar").toURL())
        def CoordinateTransformer = Class.forName("de.is24.gis.geotools.CoordinateTransformer").newInstance();

        def x = doc.realEstateCommonData.locationDto.geoCoordinateDto.xCoordinate;
        def y = doc.realEstateCommonData.locationDto.geoCoordinateDto.yCoordinate;

        def coords = CoordinateTransformer.transformFromLambertEuToWgs84(x,z)

        println coords.getLatitude()
        println coords.getLongitude()
        def jsonObj = new JsonSlurper().parseText( '{"type" : "Point", "coordinates" : [' + coords.getLatitude() + ',' + coords.getLongitude() + ']}' )

        doc.location = jsonObj       
    }
}
4

2 回答 2

0

不知道为什么您无法访问 rooLoader,这一定与此 Groovy 脚本的执行方式有关。

你可以试试这个(显然未经测试)

class GeoTransformer {
    void transform( doc ) {
        def urlLoader = new GroovyClassLoader()
        urlLoader.addURL( new File("gis-geotools-1.9.0.jar").toURL() )

        def coordTransformer = Class.forName( "de.is24.gis.geotools.CoordinateTransformer",
                                              true,
                                              urlLoader ).newInstance()

        def x = doc.realEstateCommonData.locationDto.geoCoordinateDto.xCoordinate;
        def y = doc.realEstateCommonData.locationDto.geoCoordinateDto.yCoordinate;

        def coords = coordTransformer.transformFromLambertEuToWgs84( x, z )

        println coords.latitude
        println coords.longitude

        doc.location = [ type:'Point',
                         coordinates:[ coords.latitude, coords.longitude ] ]
    }
}

我摆脱JsonSlurper了底部的位,直接创建了地图(我假设doc.location需要是地图)?

编辑:

这适用于 Groovy 控制台:

def jar = new File( '/path/to/commons-collections-3.2.1.jar' )
def loader = new GroovyClassLoader()
loader.addURL( jar.toURL() )

def bag = Class.forName( 'org.apache.commons.collections.bag.HashBag',
                         true,
                         loader ).newInstance()
bag.add( 'tim' )

println bag
println bag.getClass().name

并打印:

[tim]
org.apache.commons.collections.bag.HashBag
于 2013-08-21T09:12:30.543 回答
0

通过 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()直到找到一个RootLoader 的实例。如果不是,它会发现 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;
}
于 2017-03-09T21:27:49.273 回答