Jason,
thanks for a quick response!
On 29. 3. 2016, at 19:09, "Winnebeck, Jason"
wrote:
> You still have to follow the rules of Java bytecode
right, that's why I wrote it's a Java fault (inherited by Groovy), not a Groovy
fault.
> that is your class DumbProxy is not related by class hierarchy or interface
> to AnyClassOfMine, so you can't cast to it.
That is precisely the problem: without casting to it, it can't be used.
> You have to use def/Object type and Groovy's duck typing, or you need to make
> DumbProxy extend AnyClassOfMine
Far as I understand the Groovy dispatch, this would force me not to go through
a relatively clean missingXXX APIs; instead, I would probably have to exploit
metaclass functionality directly, or something like that.
Well OK, that I can live with (unless it gets really slow, which it probably
would not).
But what if the target class is final? Would never happen with AnyClassOfMine
of course, but would happen with 3rd party classes whose instances I might need
to proxy.
> or make an interface for them both to implement and use that.
Same problem there: whilst I can turn AnyClassOfMine to implement anything, I
can't turn 3rd party classes to do that; and proxying 3rd party classes is
essential (after all, with my own classes I can easily use other tricks than
proxying to achieve the same result).
> Other options to consider include:
> http://docs.groovy-lang.org/latest/html/gapi/groovy/util/Proxy.html
Correct me please if I am overlooking anything, but it seems to me this is just
slightly better implementation of DumbProxy. To redirect methods it uses
invokeMethod instead of methodMissing (perhaps it is faster? Dunno. One
advantage might be it would technically allow to forward even methods
implemented in Proxy itself, but that is prevented by the implementation); but
it _does_ share the very same typecasting problem we have just established with
my DumbProxy.
Or does it not? If not, how comes?
> http://docs.groovy-lang.org/latest/html/gapi/groovy/util/ProxyGenerator.html
Well this seems really to create an instance of a dynamically made subclass
(whoa! But I can see there's nothing else we can do with the bloody Java
inherited behaviour), but I must be missing something. That instance does not
work as a proxy, but seems to be half-proxy half-real instance of the target
class.
Far as I has been able to test, it seems that
pg.instantiateDelegateWithBaseClass([:],[],delegate,class)
(a) creates a new instance of (a private subclas of) given “class” (OK)
(b) which instance gets all the methods (including property getters and
setters) “class” contains, directly, without notifying the “delegate” anyhow
(COMPLETELY WRONG)
(c) and only properties a methods the “class” does _not_ contain are directed
to the delegate (OK)
The functionality needed for proxying differs from that:
(a) the proxied object (a server) exists before a proxy is created;
(b) the delegate (far as I understand what is its purpose?!?) should get _all_
the methods called “of the proxy”...
(c) ... so that it can (pre- or post-process them if need be and) forward them
to the real proxied object.
Here's my testing code; perhaps you can point out what's wrong? The
documentation is seriously lacking :)
===
class AnyClassOfMine {
def xxname // renamed from 'name' to be triple sure not to clash with proxy
name or something
def foo(bar) { println "foo of $this called with $bar";
"${bar.toUpperCase()}, I am $xxname" }
}
class Delegate {
def server
def propertyMissing(String name) {
println "- delegate asked for a property '$name' for server $server"
if (name!='xxname') return 'nonexistent'
server."$name"
}
def propertyMissing(String name,value) {
println "- delegate asked to set a property '$name' to $value for server
$server"
if (name!='xxname') return 'nonexistent'
server."$name"
}
def methodMissing(String name, args) {
println "- delegate asked for a method '$name'$args for server $server"
if (name!='foo') return 'nonexistent'
server."$name"(*args)
}
}
def proxied=new AnyClassOfMine(xxname:"Proxied"),delegate=new
Delegate(server:proxied)
assert delegate.xxname=='Proxied'
def pg=groovy.util.ProxyGenerator.INSTANCE // is this the proper way to do it?
def
proxy=pg.instantiateDelegateWithBaseClass([:],[],delegate,delegate.server.class)
assert proxy instanceof AnyClassOfMine
println "=== Delegate gets unknown method allright:"
println "-> ${proxy.unknown('hello')}"
println "=== Known method implemented by $proxy, instead of being sent through
delegate to $proxied!"
println "-> ${proxy.foo('hello')}"
println "=== It should look like this:"
println "-> ${delegate.foo('hello')}"
println "=== Exactly same problem with properties: unknown one correctly
forwarded..."
println "-> $proxy.unknownProperty"
println "=== Known property though processed directly by proxy, not forwarded
through