1

I have a setup in Eclipse Mars where there are two dependencies. Both are the same program but are different versions. In this program, there is a class called InitialHandler. The constructor of this class has changed between the two versions of the program from InitialHandler(ProxyServer, ListenerInfo) to InitialHandler(BungeeCord, ListenerInfo). BungeeCord is a subclass of ProxyServer.

I am trying to make a class that is compatible with both the new and legacy versions of the constructor. To do this, my class also has two constructors taking the respective parameters as input. Problem is, in the constructor that is supposed to take the BungeeCord input, the super() call is still using the constructor from the old dependency, which uses ProxyServer. See a screenshot here

How do I force the super() call to use the version of the constructor with the BungeeCord parameter?

Evan McCoy
  • 11
  • 3

1 Answers1

0

I came up with a solution that could work in your scenario, but it works a little bit differently than what you initially wanted to solve (the resolving of super calls):

public class OpenInitialHandler extends InitialServerLegacyDelegate {

    public OpenInitialHandler(BungeeCord bungee, ListenerInfo listener) {
        super(bungee, listener);
    }

    public OpenInitialHandler(ProxyServer proxyServer, ListenerInfo listener) {
        super(proxyServer, listener);
    }
}
public class InitialServerLegacyDelegate /* implements and extends whatever you need */ {

    private static final Constructor<InitialDelegate> targetConstructor = InitialServer.getConstructors()[0];

    private final InitialServer delegate;

    protected InitialServerLegacyDelegate(BungeeCord bungee, ListenerInfo listener) {
        this(bungee, listener);
    }

    protected InitialServerLegacyDelegate(ProxyServer proxyServer, ListenerInfo listener) {
        try {
            // This is the critical part.
            // Instead of binding/checking the constructor parameter types
            // at compile-time, this will be resolved at runtime.
            delegate = targetConstructor.newInstance(proxyServer, listener);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    // implement all neccessary interface methods here
    // and simply make them delegate methods
}

Essentially, the InitialServerLegacyDelegate handles this legacy behaviour. It looks like a valid superclass (because it implements the same interfaces like InitialServer, but in reality it just delegates all calls to an instance of InitialServer which it resolves at runtime.

One problem you might be facing is: If your class gets a input at OpenInitialHandler(ProxyServer proxyServer, ListenerInfo listener) where ProxyServer is not of type BungeeCord. In this case, the implementation will fail with a ClassCastException if the newer dependency (with the BungeeCord constructor) is present and it gets a non-BungeeCord-input.

Delegate methods can easily be generated by Eclipse. For more detail, see this question on how to generate delegate methods in Eclipse.

Community
  • 1
  • 1
randers
  • 5,031
  • 5
  • 37
  • 64