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