JDK 8 - Lambda - Reflection issues

Remi Forax forax at univ-mlv.fr
Fri Mar 14 18:26:40 UTC 2014


On 03/14/2014 05:43 PM, Pavel Bucek wrote:
> 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

You should do submit a bug, so we will document for everyone why this 
issue is invalid :)

cheers,
Rémi


>
> 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