java - Groovy 扩展模块方法 - 无方法签名

标签 java gradle groovy jar urlclassloader

我在 java.util.ArrayList() 上创建了两个 groovy 扩展模块/方法。这一切在我的 IDE 中运行得很好。我使用 gradle 构建 jar,并将其部署到远程 JVM。当它到达远程 JVM 时,它会失败。

这是扩展方法:

    static Map sumSelectedAttributes(final List self, List attributes) {
    Map resultsMap = [:]
    attributes.each { attr ->
        resultsMap[attr] = self.inject(0) { sum, obj ->
            sum + obj[attr]
        }
    }
    return resultsMap

这是调用它的代码:

outputMap[processName][iName] << kBeanList.sumSelectedAttributes([
    "messageCount", "userCount", "outstandingRequests",
    "cpuUsage", "memoryUsage", "threadCount", "cacheCount", "huserCount",
    "manualHuserCount", "dataPointerCount", "tableHandleCount",
    "jdbCacheRecordCount", "dbConnectionCount"])

错误如下:

No signature of method: java.util.ArrayList.sumSelectedAttributes() is applicable for argument types: (java.util.ArrayList) values: [[messageCount, incomingConnectionsCount, outgoingConnectionsCount, ...]]

同样,它在带有测试用例的 intellij 中运行良好。远程 JVM 上有什么不同会阻止其工作?以下是我想到的一些事情:

  1. 远程 JVM 使用 Groovy 2.3,而我使用的是 2.4.5
  2. 我们在远程 JVM 上使用自定义类加载器来加载类

除此之外,我找不到任何其他有关使扩展在远程 JVM 上运行所需的特殊操作的文档。

非常感谢任何帮助。

根据评论,似乎是自定义类加载器的问题,这里是处理一些类加载器的操作的类。

class CustomLoader {
    static Map loaders = [:]
    static File loaderRoot = new File("../branches")

    static URLClassLoader getCustomLoader(String branchName) {
        if (!loaders[branchName]) {
            loaders[branchName] = new URLClassLoader(getUrls(branchName))
        } else {
            loaders[branchName]
        }
    }

    static URLClassLoader updateClassLoader(String branchName) {
        loaders[branchName] = null
        loaders[branchName] = new URLClassLoader(getUrls(branchName))
    }

    private static URL[] getUrls(String branchName) {
        def loaderDir = new File(loaderRoot, branchName)
        List<File> files = []
        loaderDir.eachFileRecurse{
            if (it.name.endsWith('.jar')) {
                files  << it
            }
        }
        List urls = files.sort{ it.name }.reverse().collect{it.toURI().toURL()}
        return urls
    }
}

最佳答案

要手动注册扩展方法模块,您可以使用类似于 GrapeIvy 中使用的代码。因为葡萄有同样的问题,它们使 jar 在错误的加载器中可见,但仍然想要启用扩展方法。有问题的代码如下:

JarFile jar = new JarFile(file)
def entry = jar.getEntry(ExtensionModuleScanner.MODULE_META_INF_FILE)
if (entry) {
  Properties props = new Properties()
  props.load(jar.getInputStream(entry))
  Map<CachedClass, List<MetaMethod>> metaMethods = new HashMap<CachedClass, List<MetaMethod>>()
  mcRegistry.registerExtensionModuleFromProperties(props, loader, metaMethods)
  // add old methods to the map
  metaMethods.each { CachedClass c, List<MetaMethod> methods ->
    // GROOVY-5543: if a module was loaded using grab, there are chances that subclasses
    // have their own ClassInfo, and we must change them as well!
    Set<CachedClass> classesToBeUpdated = [c]
    ClassInfo.onAllClassInfo { ClassInfo info ->
      if (c.theClass.isAssignableFrom(info.cachedClass.theClass)) {
        classesToBeUpdated << info.cachedClass
      }
    }
    classesToBeUpdated*.addNewMopMethods(methods)
  }
}

在此代码文件中是一个代表 jar 的文件。对于你的情况,你需要在这里有其他东西。基本上,我们首先将描述 rune 件加载到 Properties 中,调用 registerExtensionModuleFromProperties 来根据给定的类加载器使用 MetaMethods 填充映射。这是解决问题的关键部分,正确的类加载器可以加载扩展模块和 groovy 运行时中的所有类!此后,任何新的元类都会了解扩展方法。仅当已经存在元类并且您想了解这些新方法时才需要下面的代码。

关于java - Groovy 扩展模块方法 - 无方法签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36762144/

相关文章:

java - Groovy 用可能的字符串分割字符串

groovy - 在 groovy 中从闭包中引用私有(private)成员变量是否合法?

java - 使用 Apache Axis2 和 Tomcat 版本 7 的 Web 服务出现问题

gradle - 在多项目构建中依赖多个gradle任务

Groovy 比较两个字符串

android - 用 Guava 编译谷歌云服务客户端库

Android Studio 总是为每个新项目下载 gradle?

java - 获取空或 null SecurityContextHolder.getContext().getAuthentication()

Java 使用新类向现有类添加功能,同时仍然公开先前类的所有方法

java - 使用 Apache POI 更改 Excel 折线图中的数据范围