On 10/15/2014 06:54 PM, Paul Sandoz wrote:
Hi Remi,
I did some brief evaluation of this area.
MethodHandleProxies.asInterfaceInstance currently does not support proxying to
default methods. An InternalError will be thrown if a default method is
invoked. It should be possible to fix using a trusted internal IMPL_LOOKUP to
look up MHs that invokespecial. I believe this should be safe under the context
of proxying.
Another solution is to do not rely on j.l.r.Proxy to implement
asInterfaceInstance but to generate a proxy using ASM,
in that case, handling default methods is easy, just do nothing (i.e. do
not override a default method).
It will also solve the fact that the proxies generated by
asInterfaceInstance are currently super slow
because of the InvocationHandler API require boxing.
The real solution in my opinion is to create yet another API, lets call
it proxy 2.0 that takes an interface and a bootstrap method
as parameter and generate a class that will call the BSM when calling a
method of the proxy class the first time
(the BSM will be called with a 4th parameter which is a method handle
corresponding to the called method
so one can use MHs.reflectAs to get the corresponding j.l.r.Method
object if necessary).
For a default method, the 4th parameter will be a method handle created
with findSuper, so a user can choose
to implement it or to delegate to this mh.
And asInterfaceInstance is just a foldArguments between the method
handle taken as parameter and
an exactInvoker (or a genericInvoker if parameter types mismatch).
Compared to a j.l.r.Proxy, the proxy 2.0 API also need a way to store
fields (or at least values) inside the generated proxy class
and a way to query that fields inside the BSM. This can be done exactly
like this is done by the lambda proxy,
instead of returning a proxy class, the proxy 2.0 API will return a
method handle that acts as a factory for creating
proxy instances of the proxy class (if the factory takes no arguments,
as for the lambda proxy, the same constant object can be returned).
To get a mh getter from inside the BSM, because the BSM already have the
lookup object, all you need is a convention that says
that the field names are something like arg0, arg1, etc.
The nice thing about this API is that it cleanly separate the
information that can be process from proxied interface(s)
(by example, JavaEE annotations) and the ones, more dynamic, that are
specific to a proxy instance.
It also removes one level of indirection compared to the
InvocationHandler proxy.
The InvocationHandler case is a little more tricky (as you show below). There
could be a static method on MethodHandleProxies that returns an
InvocationHandler that if proxying to default methods gives the option to
continue with the default or not. The InvocationHandler, on invocation, must
verify that it's arguments are valid before proxying to a default method i.e. p
is an instance of a proxy class. Under such circumstances i believe that should
be safe.
Paul.
Rémi
On Oct 9, 2014, at 7:07 PM, Remi Forax <fo...@univ-mlv.fr> wrote:
public static void main(String[] args) throws NoSuchFieldException,
IllegalArgumentException, IllegalAccessException {
Lookup lookup = MethodHandles.publicLookup().in(Consumer.class);
Field allowedModes = Lookup.class.getDeclaredField("allowedModes");
allowedModes.setAccessible(true);
allowedModes.set(lookup, Modifier.PRIVATE);
@SuppressWarnings("unchecked")
Consumer<Object> consumer = (Consumer<Object>)Proxy.newProxyInstance(
CallingADefaultMethodInAProxy.class.getClassLoader(),
new Class<?>[]{Consumer.class},
(Object proxy, Method method, Object[] array) -> {
if (method.isDefault()) {
MethodHandle mh = lookup.unreflectSpecial(method, Consumer.class);
return mh.invokeWithArguments(Stream.concat(Stream.of(proxy),
Arrays.stream(array)).toArray());
}
System.out.println("hello");
return null;
});
consumer.andThen(System.out::println).accept("default method");
}
Not very pretty, if someone ask me I will deny to have written that code :)
John, I've discovered that findSpecial/unreflectSpecial doesn't honor
setAccessible,
given that the whole point of unreflectSpecial is to see a virtual call as a
super call,
it looks like a bug to me.
Rémi
On 10/09/2014 04:42 PM, Jochen Theodorou wrote:
too bad no-one knows. Has anyone an idea for a better place to ask this? (btw,
because of the getSimpleName issue I can't use MethodHandleProxies)
Am 06.10.2014 18:06, schrieb Jochen Theodorou:
Hi,
I find this a little odd and I wonder how you are supposed to do it
right. Or if that is a bug.
So I have a class implementing InvocationHandler and I used Proxy to
create a an proxied instance of Consumer. This is a functional interface
and I want to use its accept method for my purposes, while still keeping
the old andThen method as it is.
going by the usual signature for the InvocationHandler implementation
main method (public Object invoke(Object proxy, Method method, Object[]
args) throws Throwable)
I can do neither method.invoke on this, since that leads to that method
(overflow then) again, nor can I take the proxy object, since it
obviously has nothing to do with functional interface.
Now... is that really on purpose? Are you indeed forced to split up your
code into a java7+ and pre java7 case to be able to use
MethodHandleProxies#asInterfaceInstance where it is available instead?
Shouldn't Proxy and InvocationHandler then be marked deprecated in
Java8? And how do you use MethodHandleProxies to implement multiple
interfaces?
bye Jochen
_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev