NoSuchMethodException - 方法的 return 类型已更改 - 想要接受两种类型

NoSuchMethodException - method's return type has changed - Want to accept both types

背景

我有一个必须更新的公共库。这个公共库有一个第三方依赖(jgroups),它在新版本中发生了重大变化。通过传递依赖,有时需要更新版本的 jgroups,这会破坏公共库。我需要更新一些 classes 以与新版本兼容,同时保持向后兼容性。

问题

JGroups提供了一个Viewclass,其中有一个方法getMembers()。在旧版本 (2.10.0) 中,此方法 returns Vector<Address>,在较新版本 (3.2.7) 中,此方法 returns List<Address>java.util.Collection 的任何实现都适用于我,但问题是我得到的是 NoSuchMethodException。据我了解,找到的 getMembers() 方法具有遗留的 Vector<Address> return 类型(基于公共库中的 JGroups 依赖项),但我正在拖入较新的 JGroups 版本并且View class 期望 List<Address> return 来自 getMembers() 方法。

堆栈跟踪

在 Eclipse 中启动我的应用程序时出现以下错误。

Caused by: java.lang.NoSuchMethodError: org.jgroups.View.getMembers()Ljava/util/Vector;
    at com.mycompany.commons.messaging.events.impl.distributed.JGroupsEventDistributionProvider$JGroupsEventReceiver.viewAccepted(JGroupsEventDistributionProvider.java:136) ~[classes/:na]
    at org.jgroups.JChannel.invokeCallback(JChannel.java:752) ~[jgroups-3.2.7.Final.jar:3.2.7.Final]
    at org.jgroups.JChannel.up(JChannel.java:710) ~[jgroups-3.2.7.Final.jar:3.2.7.Final]
    at org.jgroups.stack.ProtocolStack.up(ProtocolStack.java:1020) ~[jgroups-3.2.7.Final.jar:3.2.7.Final]
    at org.jgroups.protocols.pbcast.FLUSH.up(FLUSH.java:466) ~[jgroups-3.2.7.Final.jar:3.2.7.Final]
 ....

断的地方

Collection<Address> viewMembers = view.getMembers();

问题

是否可以同时支持这两个版本,即使它们是 Collection 的不同实现?在运行时之前我不知道方法 return 类型,我该如何处理这种情况?

注:

我试图通过在我的 maven pom.xml 中添加排除来排除正在引入的旧版本 JGroups。这没有用。

    <dependency>
        <groupId>com.mycompany.commons</groupId>
        <artifactId>mycompany-commons-event-distributed-jgroups</artifactId>
        <!-- Note: JGroups dependency is provided by infinispan -->
        <version>1.0.2-SNAPSHOT</version>
        <type>jar</type>
        <scope>compile</scope>
        <exclusions>
            <exclusion>
                <groupId>org.jgroups</groupId>
                <artifactId>jgroups</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

如果您使用 "plain java" 作为应用程序框架,我认为您通常不太走运。

如果不使用某种模块框架(例如 OSGI),您只有一个 classes 池,每个 class 加载到您的 classpath 都会进入该池。这意味着您不能在 JVM 中同时拥有同一个 JAR 或同一个 class 的多个版本。

此外,您必须支持同一个 JAR 的多个版本,因为您至少有两段代码分别针对不同的版本进行编译:一段代码期望 Vector 的 return 值和List 中的另一个,因此即使您可以将不需要的代码从构建环境中隔离出来,针对它构建的代码也不会 link 到正确的二进制文件,您将继续获得 运行你看到的时间异常。

不幸的是,您提到这是一个 "library" 而不仅仅是一个应用程序,这可能会使应用解决方案变得更加困难。在我的脑海中,我看到了这些可供您前进的选项,none 其中微不足道,有些可能无法实现:

  1. 根据需要将您的代码降级为在所有依赖链中只有一个版本的 jgroups
  2. 重新构建您的应用程序以使用 OSGI 或支持同一库的多个版本的类似框架,因此依赖链可能会发生分歧
  3. 重新构建您的应用程序并将其分成多个 运行 在它们自己的 JVM 中,通过套接字或任何其他方式进行通信

例如,我们使用了第三个选项来拆分应用程序的一小部分,因此它可能依赖于许可证对我们整个代码库不友好的库,但该部分可以与库一起获得许可。

我也不确定 Java 9 模块系统对此有何反应,但它可能在 运行 时间内同时支持同一模块的多个版本。如果您可以选择使用该测试版或进行调查,那可能值得您付出努力。但是,您提到要点是向后兼容性,因此这也可能不是一个可行的选择。

使用反射怎么样? FieldView.members是2.10.x中的Vector,3.x中是Address[]数组。您可以访问字段 View.members 并且 - 根据其类型 - return 所有成员作为地址集合。不太好,但应该有用..