JDK 8 - Lambda - Reflection issues
Simone Bordet
simone.bordet at gmail.com
Fri Mar 14 22:07:53 UTC 2014
Hi,
> On 03/13/2014 09:56 AM, Pavel Bucek wrote:
>> 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 -> {
>> // ...
>> });
As another co-implementor of JSR 356 in Jetty, I wanted to express the
same concerns as Pavel.
On Fri, Mar 14, 2014 at 7:14 PM, Remi Forax <forax at univ-mlv.fr> wrote:
> I should have written a blog post on that subject a long time ago,
> doing runtime inspection of type information used by javac in a library is
> usually harmful,
> here is why.
>
> 1) Java is not the only language on the JVM, the other compiler/runtime
> doesn't necessarily have type information,
> by requiring type information you consider groovy, nashorn, jruby, etc
> guys as second citizens.
Very good point.
> 2) The code that does the introspection is hard to get right,
> a simple example that shows that you have to do type propagation:
> interface Foo<I> extends MessageHandler.Whole<I> { }
> class Bar extends Comparable<Integer>, Foo<String> { ... }
> session.addMessageHandler(new Bar());
>
> 3) At runtime, it can be very slow because it may have to crawle all the
> super types,
> and look for a fix point when you have types that have recursive bounds
> (like enums or comparable)
>
> 4) Let suppose the introspection code found a type, then it usually relies
> on an implicit configuration
> to find how to convert the value (usually a String) to the type.
> Implicit configuration == nigthmare when testing if the configuration
> used by the user code
> is not the default one
>
> So instead of using a broken idiom, I think it's better to explicitly
> specify the conversion
> using either a lambda or better a method reference as first parameter.
>
> session.addMessageHandler(Integer:parseInt, integer -> ...);
> session.addMessageHandler(Paths::get, path -> ...);
In JSR 356 the type T in Whole<T> is used to select a "deserializer"
that converts the bytes in the WebSocket message to an object of type
T.
"Deserializers" are configurable by the application.
If I understand correctly Rémi suggestion, he's saying to change the
signature to accept a "converter" from String/byte[] to something
(above expressed as a method reference) and then feed the result of
that to the lambda.
addMessageHandler(Function<String, B> f, MessageHandler<B> h)
It would be probably much simpler to get rid of "deserializers" in JSR
356, and stick with String and byte[], and possibly streams and
readers.
The application does the rest.
Not that it will fix the problem at hand, and just for sake of
discussion, has the idea of an annotation that enforces *not* to
convert to a lambda been explored by experts ?
@NONFunctionalInterface
interface Foo<T> { void foo(T t); }
interface Bar { void <T> accept(Foo<T> foo); }
class Main {
void main(String[] a) {
Bar bar = ...;
bar.accept((String s) -> { ... }); // Does not compile
}
}
Thanks !
--
Simone Bordet
http://bordet.blogspot.com
---
Finally, no matter how good the architecture and design are,
to deliver bug-free software with optimal performance and reliability,
the implementation technique must be flawless. Victoria Livschitz
More information about the jdk8-dev
mailing list