invoking a interface default method from within an InvocationHandler
Jochen Theodorou
blackdrag at gmx.org
Thu Oct 9 17:30:01 UTC 2014
Am 09.10.2014 19:07, schrieb Remi Forax:
> 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 :)
lol.
The other variant is to get the Lookup constructor accepting an int, to
make private level access possible. But is that really supposed to be a
standard solution? I mean I could then use Unsafe too ;)
> 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.
yes, I found the same thing strange... though given the special nature
of invokespecial I was thinking that this limitation is there to ensure
this "call has to be done from same class or subclass" logic. So I would
expect for example, that if I do MethodHandles.lookup().in(Foo.class),
while being in Foo or a subclass that it would work. But of course, that
is of zero use if Foo is an interface and whole purpose of the exercise
is to have a proxy that acts as that interface instead of having to
implement the interface yourself. But I did not actually test if my
assumption is right.
bye Jochen
--
Jochen "blackdrag" Theodorou - Groovy Project Tech Lead
blog: http://blackdragsview.blogspot.com/
german groovy discussion newsgroup: de.comp.lang.misc
For Groovy programming sources visit http://groovy-lang.org
More information about the mlvm-dev
mailing list