JDK 8 - Lambda - Reflection issues

Pavel Bucek pavel.bucek at oracle.com
Fri Mar 14 16:43:09 UTC 2014


I'm considering filing this as a backward compatibility issue against 
JDK 8 - my reasoning would be that I should be able to still get the 
same information from the reflection API as I did in previous versions 
of JDK and I don't have a way how to restrict lambda usage in the 
already designed and published API.

Can anyone give me any reason why shouldn't I do that? (I suspect 
something like "read [this][link] document, where we explicitly say that 
this is to be expected thus the issue is invalid".

Thanks!
Pavel

On 13/03/14 10:10, Pavel Bucek wrote:
> 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