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