dimanche 29 septembre 2019

Implementing equals, hashCode, and toString on java.lang.reflect.Proxy

I'm writing an application where I need to implement functional interfaces on runtime. I don't know in advance which interfaces to implement, but can resolve the Method object using reflection from the interface's Class object.

For the purpose of simplifying the question, let's say that I'm passing a Function object containing the implementation of the method.

Straight-forward stuff:

@SuppressWarnings("unchecked")
private <T> T implement(Class<T> interfaceType, Method m, Function<Object[], ?> f) {
    return (T) Proxy.newProxyInstance(
            getClass().getClassLoader(),
            new Class<?>[]{interfaceType},
            (proxy, method, args) -> {
                if (method.equals(m)) {
                    return f.apply(args);
                }

                // Calls to toString, hashCode, and equals go here.
                throw new UnsupportedOperationException(method.getName());
            }
    );
}

So calls to toString, hashCode, and equals currently fail. I clearly don't want that.

From the docs of java.lang.reflect.Proxy:

An invocation of the hashCode, equals, or toString methods declared in java.lang.Object on a proxy instance will be encoded and dispatched to the invocation handler's invoke method in the same manner as interface method invocations are encoded and dispatched, as described above. The declaring class of the Method object passed to invoke will be java.lang.Object. Other public methods of a proxy instance inherited from java.lang.Object are not overridden by a proxy class, so invocations of those methods behave like they do for instances of java.lang.Object.

So I can override these methods however I want. That's cool, but I would prefer not to.

Sure, I could make dummy implementations that do more or less the same thing (except for hashCode which is native) or capture some other dummy object (maybe the invocation handler itself) and invoke the method on that one. But I feel like I should be able to just "fall through" to the methods inherited from java.lang.Object the usual way. Or in other words, call the equivalent of super.hashCode() etc. directly on proxy.

Is there a good/standard way of doing that?





Aucun commentaire:

Enregistrer un commentaire