Search code examples
javaeclipsemavenjgroupstransitive-dependency

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


Background

I have a commons library that I have to update. This commons library has a third party dependency (jgroups) which was changed significantly in newer versions. Through transitive dependencies, the newer version of jgroups is sometimes required and this breaks the commons library. I need to update some classes for compatibility with newer versions, while maintaining backwards compatibility.

The Problem

JGroups provides a View class, which has a method getMembers(). In the old version (2.10.0), this method returns Vector<Address> and in the newer version (3.2.7), this returns List<Address>. Any implementation of java.util.Collection will work for me, but the problem is I'm getting a NoSuchMethodException. As I understand it, the getMembers() method found has the legacy Vector<Address> return type (based on the JGroups dependency in the commons library), but I am dragging in a newer JGroups version and that View class expects a List<Address> returned from the getMembers() method.

Stacktrace

I get the following error when starting up my application in 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]
 ....

Where it breaks

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

Question

Is it possible to support both versions, even though they are different implementations of Collection? How can I handle this scenario where I don't know the method return type until runtime?

Note:

I have tried to exclude the older version of JGroups that is being pulled in by adding an exclusion in my maven pom. This has not worked.

    <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>

Solution

  • How about using reflection ? Field View.members is a Vector in 2.10.x and an Address[] array in 3.x. You could access field View.members and - depending on its type - return all members as a collection of addresses. Not nice, but should work..