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