JDK 8 - Lambda - Reflection issues
Pavel Bucek
pavel.bucek at oracle.com
Thu Mar 13 09:10:46 UTC 2014
just for the sake of correctness - WholeMessageHandler<T> does not need
to have Class<T> genericParam field and constructor param - anonymous
class which just wraps the lambda expression is good enough.
On 13/03/14 09:56, Pavel Bucek wrote:
> Hi Remi,
>
> thanks! I suspected that it would not be possible, but it is always
> better to have the confirmation.
>
> My context is slightly different, but the consequences are similar
> like with the jackson library. Seems a little unfortunate to have the
> possibility to use lambdas even on places where it cannot work - my
> guess is that this will become one of most frequent question on some
> mailing lists..
>
> (you don't really need to read further)
>
> I'm working on JSR 356 - Java API for WebSocket implementation and
> there is an interface:
>
> interface MessageHandler.Whole<T> extends MessageHandler {
> void onMessage(T message);
> }
>
> And then there is a Session object, which has method "void
> addMessageHandler(MessageHandler handler);". Obvious common use of
> this method is:
>
> session.addMessageHandler(new MessageHandler.Whole<String>() {
> @Override
> public void onMessage(String message) {
> // ...
> }
> });
>
> I can see my IDE automatically offers me to transform this to lambda
> expression (this is actually what worries me a little, because all
> users will see that and do it - because why not - it seems to be
> equivalent with anonymous class). When this suggestion is accepted,
> previous statement is transformed into:
>
> session.addMessageHandler((MessageHandler.Whole<String>) message -> {
> // ...
> });
>
> which looks prettier, but just does not work and cannot work :/ I
> guess we could provide wrapper class, something like:
>
> public static class WholeMessageHandler<T> implements
> MessageHandler.Whole<T> {
>
> private final Class<T> genericParam;
> private final MessageHandler.Whole<T> wholeMessageHandler;
>
> protected WholeMessageHandler(Class<T> genericParam,
> MessageHandler.Whole<T> wholeMessageHandler) {
> this.genericParam = genericParam;
> this.wholeMessageHandler = wholeMessageHandler;
> }
>
> public Class<T> getGenericParam() {
> return genericParam;
> }
>
> @Override
> public void onMessage(T message) {
> wholeMessageHandler.onMessage(message);
> }
> }
>
> and then, when user would want to use lambdas, do it with help of that
> class:
>
> session.addMessageHandler(new WholeMessageHandler<Main>(Main.class,
> param -> System.out.println("234")));
>
> so I can do this like a workaround, but anyway, the initial
> recommendation of the IDE is bad enough to cause us lots of mailing
> list traffic and explanations why is not possible to use lambda in
> "native" fashion. Anyway - I'm not describing my pain just to share my
> pain - if anyone have any suggestions how this can be solved, I'm all
> ears; any reply would be greatly appreciated.
>
> Thanks!
> Pavel
>
>
> On 12/03/14 19:42, Remi Forax wrote:
>> On 03/12/2014 07:12 PM, Pavel Bucek wrote:
>>> Hello all,
>>>
>>> I have an issue with getting generic parameter when using lambdas. I
>>> can get the type when using anonymous classes.
>>>
>>> code sample will be more descriptive than anything I would say, so.. :
>>>
>>> public class Main {
>>>
>>> public static interface A<T> {
>>> public void method(T param);
>>> }
>>>
>>> public static void main(String[] args) {
>>>
>>> final A<Main> anonClass = new A<Main>() {
>>> @Override
>>> public void method(Main param) {
>>> System.out.println("234");
>>> }
>>> };
>>>
>>> final A<Main> lambda = param -> System.out.println("234");
>>>
>>> //following does not help.
>>> // final A<Main> lambda = (A<Main>)param ->
>>> System.out.println("234");
>>>
>>>
>>> // output: Main.Main$A<Main>
>>> System.out.println("$ " +
>>> anonClass.getClass().getGenericInterfaces()[0]);
>>>
>>> // output: interface Main$A ### generic type info
>>> is already lost (no <Main>)
>>> System.out.println("# " +
>>> lambda.getClass().getGenericInterfaces()[0]);
>>>
>>> // parameterized type from annon class
>>> final Type t =
>>> ((ParameterizedType)anonClass.getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0];
>>> System.out.println("$ " + t);
>>>
>>> // parameterized type from lambda
>>> System.out.println("# " + "???");
>>> }
>>> }
>>>
>>> I was not able to find any useful documentation or article about
>>> this, so sorry if this is something common - feel free to RTM me
>>> (with relevant link please).
>>>
>>> Thanks and regards,
>>> Pavel
>>
>> As you have seen a lambda is not an anonymous class :)
>>
>> A non-serializable lambda is more lightweight than an anonymous class
>> so the generic information that are transmitted from the bytecode to
>> the runtime (the lambda metafactory) are not kept inside the lambda
>> class (a lambda class may be shared by several different lambdas).
>>
>> A serializable lambda keep these information because you need them to
>> deserialize a lambda but they are not publicly available
>> The current implementation encoded them in the bytecode and this
>> bytecode is not publicly available so unless you serialize the lambda
>> and serialize it by hand, you can not have access to these information.
>>
>> So you can not use a lambda with frameworks like Jackson that use the
>> TypeReference idiom,
>> you can still use an anonymous class for that :)
>>
>> cheers,
>> Rémi
>>
>>
>>
>
>
>
More information about the jdk8-dev
mailing list