Tuesday Mar 18, 2014

WebSocket API in JDK 8 - MessageHandler issue

JDK 8 is not yet released and it is already causing some headaches for JSR 356 implementors. The issue described in this article will be about the most famous and anticipated JDK 8 feature – lambda expressions and its impact to one part of WebSocket API.

Lambda expressions usable in WebSocket API can be diminished to just a replacement for standard anonymous classes; there might be some places where you can use method references, but not in the case of message handler. Following text is mainly about addMessageHandler method:

1
2
3
public interface Session extends Closeable {
void addMessageHandler(MessageHandler handler) throws IllegalStateException;
}

There are multiple use cases when addMessageHandler method is used – for example, in any endpoint based on programmatic API, which is typically true on client side. Then you have code like:

1
2
3
4
5
6
7
8
9
10
11
public class MyEndpoint extends Endpoint {
@Override
public void onOpen(Session session, EndpointConfig config) {
session.addMessageHandler(new MessageHandler.Whole<String>() {
@Override
public void onMessage(String message) {
// handle message
}
});
}
}

which always works as expected. JDK 8 introduces lambda expressions which can (not only!) replace too verbose anonymous classes, when they have only single method – which is true for MessageHandler.Whole interface. So when that code is opened in IDE supporting Java 8, it will usually say something like “anonymous class can be replaced with lambda expression” and recommends that action to be done. The resulting code will be:

1
2
3
4
5
6
7
8
public class MyEndpoint extends Endpoint {
@Override
public void onOpen(javax.websocket.Session session, EndpointConfig config) {
session.addMessageHandler((MessageHandler.Whole<String>) message -> {
// handle message
});
}
}

It is nicer, part of the information is hidden, but my guess is it might not be seen as a drawback for most cases. And 3 lines of code were saved, so thumbs up! Well.. there is the last thing.. it doesn’t work.

Lambda expressions are not anonymous classes. Anonymous class can be replaced by using lambda expression and it still compiles, but the generic parameter is lost, or at least there is no way how to obtain it via standard reflection API. And that is the problem for any JSR 356 implementation – type parameter here is used for selecting appropriate Decoder (another part of the API). Any lambda expression used instead regular generic anonymous class will be treaded as MessageHandler.Whole<Object>.

What can we do with this? Surprisingly, not much. I will try to file a backwards compatibility issue/challenge agains JDK 8, but from the initial reactions on jdk8-dev mailing list, it does not seem like something anybody is willing to fix. There is one nice constructive proposal from Simone Bordet, which would at least make the variant with lambda not compilable. That would be great workaround (which will require WebSocket API 1.0.1 release and potentially changes in other APIs), but I still consider this being an issue which should be fixed in more generic way. And last but not least – I don’t think that new version of JDK should break any existing working API.

I’ll keep this post updated whenever I got additional information. Feel free to comment or suggest a solution!

EDIT:
Credit for discovering this issue should go to user ayyrk, reporter of TYRUS-302

About

Pavel Bucek-Oracle

Search

Categories
Archives
« April 2015
SunMonTueWedThuFriSat
   
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  
       
Today