開発者注目のWebSocket。JAX-RSには大きな変更点も
Java EE 7は、下図のような構成になっている。図中の色分けの意味は次のとおりだ。
- グリーン:ビューに関わるテクノロジー
- オレンジ:Java EE全般に使えるテクノロジー
- イエロー:ビジネスロジックやデータサービスにアクセスするテクノロジー
- ブルーの線で囲まれたもの:Java EE 7で追加された新機能
WebSocket 1.0
セッションで最初に取り上げられたのは、新機能「WebSocket」である。「日本を含む世界の開発者に『Java EE 7の中でどの機能を使いたいか』というアンケートをとったところ、多くの人がWebSocketと回答した」と寺田氏が語るように、開発者が最も注目している技術だ。WebSocketを使うと、TCPベースの双方向・全二重の通信を簡単に実現できるからである。
例えば、WebSocketのアノテーションを使うと、サーバーが次のように簡単に実装できる。
@javax.websocket.server.ServerEndpoint("/chat") public class ChatServer { @OnMessage public String chat(String name, Session session) { for (Session peer : session.getOpenSessions()) { peer.getBasicRemote().sendObject(message); } } }
また、「WebSocketには、セッションのライフサイクルに沿ったコールバックメソッドがある」と寺田氏は説明を続ける。クライアントとの接続をオープンあるいはクローズした、エラーが発生した場合の処理を、次のようにOnOpen、OnClose、OnErrorというアノテーションを実装するだけで追加できる。
@javax.websocket.OnOpen public void open(Session s) { …… } @javax.websocket.OnClose public void close(CloseReason c) { …… } @javax.websocket.OnError public void error(Throwable t) { …… }
さらに、「Java EE 7のWebSocketのライブラリは、クライアントの実装も可能となっている」と寺田氏。先述のサーバーの実装にはServerEndpointというアノテーションを付加したが、クライアント実装では、次のようにClientEndpointというアノテーションを付加する。それ以外はサーバーの実装とほぼ同じだ。
@javax.websocket.ClientEndpoint public class MyClient { @javax.websocket.OnOpen public void open(Session session) { …… } // Lifecycle callbacks }
もちろん、クライアント側は、それに加えてサーバーへ接続しにいくコードも必要である。
ContainerProvider .getWebSocketContainer() .connectToServer( MyClient.class, URI.create("ws://localhost:8080/ws/hello"));
ところで、Java EE 7のWebSocketが扱えるデータは、テキストとバイナリの2種類だけである。しかし、エンコーダ(encoder)とデコーダ(decoder)を実装すると、Javaオブジェクトをメッセージとして送受信可能になる。クライアント側に情報を送る場合は、Encoder.Textを使う。これで、JavaオブジェクトからJSONなどの送信用データを生成できる。逆に、受信したデータをJavaオブジェクトへ変換するには、Decoder.Textを使う。
「このように、WebSocketを使用した実装はとても簡単。しかも標準のテクノロジーなので、GlassFishやWildFly 8など、Java EE 7に対応したアプリケーションサーバーであれば同じコードでどこでも動かすことができる。便利に使ってほしい」(寺田氏)
JAX-RS 2.0
次に寺田氏が取り上げたのは、Java EE 7で大きな変更が加わったJAX-RSである。バージョン2.0になり、スタンドアロンのアプリケーション上でもJAX-RSクライアントを作れるようになった。JAX-RSクライアントは、次のように短縮して書くことができる。
Response response = ClientBuilder.newClient() .target("http://www.foo.com/book") .request(MediaType.TEXT_PLAIN) .get();
なお、上記の実装では、レスポンスをResponseオブジェクトとして受け取る。ResponseオブジェクトからStringオブジェクトなどに変換するのが面倒なときには、次のように、getメソッドの引数にレスポンスの型を指定して受け取ることもできる。
String body = ClientBuilder.newClient() .target("http://www.foo.com/book") .request() .get(String.class);
JAX-RS 2.0では「非同期クライアント」という機能も追加された。asyncという新メソッドにより、非同期でリクエストし、その結果を非同期で受けることができる。そのメリットについて寺田氏は、「レスポンスに時間のかかる通信を行っている裏側で、別の処理を実行したいときに使える。また、サーバー側でもサスペンドとレジュームで非同期の機能を作ることができる」と説明。さらに「これにLambda式を使えば、今までより短いコードで書けるようになる」(寺田氏)。Lambda式とは、Java EE 7で追加されたExpression Language(式言語)の拡張機能である(後述)。
そのほか、JAX-RSについては、リクエスト/レスポンスのヘッダとメッセージボディに対するインターセプタ(フィルタ)が紹介された。これを使うと、例えば「If-Modified-Sinceで.getLastModifiedを指定して送り出すと、最新の情報だけを取得する」という実装が容易にできるという。ヘッダ用のインターセプタはクライアント実装用、サーバー実装用のインターフェイスが定義されている。メッセージボディ用のインターセプタは「エンティティインターセプタ」といい、Read/Write処理を実装するためのインターフェイスが定義されている。