Is there a way in java or scala, that allows to override methods of the super class in an automated fashion?
Disclaimer: i don’t pretend to be an experienced programmer, please don’t kill me for any coding-atrocities below.
I have a wrapper B of class A that does some stuff and delegates to two different instances of A. Problem is, class A has a very big number of methods. Here is my original Java implementation. It’s a monster with enormous code duplication. It works but probably contains a lots of errors, some of which maybe hard to track, some of them just will produce wrong results unnoted.
Here is my first try of a reimplementation using scala structural typing.
def get(key: Array[Byte]): Array[Byte] = {
val f: (Transaction) => Response[Array[Byte]] = _.get(key)
wrap[Array[Byte]](f, redundancySwitch, currentDB, key).get()
}
the rest is left to the common wrap function. This is already nice! But I’d still need to implement each single method individually and specifically.
My next thought was to try to have a single (reflective) generalized implementation to copy into each overriding method body, such that in definition of the function object f, there would be something to fill in the name of currently calling method.
def get(key: Array[Byte]): Array[Byte] = {
val f: (Transaction) => Response[Array[Byte]] = _.someReflectionMagic.nameOfCurrentlyCallingMethod(args)
Getting the method object is ok, but not how to pass it to f, and there doesn’t seem to be a way to get and copy the arguments of the currently called method. Here’s my aching attempt:
def zadd(key: String, score: Int, value: String) = {
// get the current Method
val thisMethod = new Object().getClass.getEnclosingMethod
val paramTypes = thisMethod.getParameterTypes
val returnType = thisMethod.getReturnType;
// this doesn't exist. how to reflectively forward parameter values (not parameter Types) into an Array for later reflective method invocation?
val params = thisMethod.getParameters
// I want to avoid to get it manually:
val params = new Array[Object]
params(0) = key
params(1) = score
params(2) = value
// this doesn't work. how to indicate the returnType here?
def f(t: Transaction): Response[returnType.class] =
t.getClass.getMethod(thisMethod.getName, paramTypes).
invoke(t,params).
asInstanceOf(Response[String])
wrap[String](f, redundancySwitch, currentDB, key).get()
}
private def getMethodName: String = {
val ste: Array[StackTraceElement] = Thread.currentThread.getStackTrace
return ste(2).getMethodName
}
this looks horrible and probably really is horrible. You experts, is there anything that could make it work? I hope at least the intention is clear?
This approach would still require having those >200 method bodies in my wrapper class. I wonder if there is any way to completely go without that:
A class B wrapping class A, that looks to the outside as if B had all methods of A, without even explicitely implementing them. When B is invoked by an A’s method x(args:T):U, auto-override / auto-delegate to a single generalized method B.y(x: T=>U).
y() would be something like the wrap() method in the second link. However, many of the above problems remain… i.e. how to capture the arguments and apply the method name on a structural typed value…
does this make sense?
This doesn’t seem to be possible with Java / java’s reflection. Is there anything in scala that could help me? Maybe some experimental scala reflection?
thanks a lot for any hints
One way would be to use java.lang.reflect.Proxy. This would require you to have an interface for all of your methods though, but you can get this reasonably easily using Refactor->Extract Interface in Eclipse.
This will give you the interface to implement in your Proxy, and you call the correct instance of A in your InvocationHandler, using reflection. The reflection may be a potential performance problem.
From the javadoc for Proxy:
EDIT: If I understand your problem correctly, you have a class B which delegates to A (or multiple As). You want to take the methods defined on class B and have them all redirect to a single method. This is exactly what a Proxy does. It works with interface, but you can get one easily enough with Extract Interface in Eclipse. The Proxy will implement that interface and redirect all calls to all methods to InvocationHandler.invoke() with the method that was called along with the instance of the object and parameters that were used.