Java における web アプリケーション開発ことはじめ (JAX-RS 2.0 / Jersey 2.4)
JAX-RS を使って Java で web アプリケーションを開発したい、と思っても、Java EE 周りに詳しくないと何をどうすればいいか全然わかんないですよね! そんなことないですか? 少なくとも私はよくわかんなかったです。
そんなわけなので、JAX-RS を使って web アプリケーションを開発しようと思った人のために、「Hello world!」 ってテキストを返すだけの web アプリケーションを作るところまで説明したいと思います。
サンプルプロジェクト
GitHub 上にサンプルプロジェクトをおいています。
Git と JDK がインストールされていれば、次のように 3 つのコマンドを実行するだけでサンプルプロジェクトを手元のサーバーで動かすことができます。
# プロジェクトをクローン git clone -b hello_world git@github.com:nobuoka/jax-rs-jersey-application-sample.git # ディレクトリ移動 cd jax-rs-jersey-application-sample # ビルドしてサーバーを起動 ./gradlew jettyRun
Web ブラウザなどで http://localhost:8080/jax-rs-jersey-application-sample/ にアクセスすると、「Hello world!」 というテキストが返ってくるはずです。 このサンプルプロジェクトの詳細をこれ以降説明していきます。
「Hello world!」 を返す JAX-RS/Jersey アプリケーションの作り方
そもそも JAX-RS とは?
REST アーキテクチャにのっとって web アプリケーションを記述するための Java の API です。 Java EE の一部として定義されています。
- JAX-RS 2.0: JSRs: Java Specification Requests - detail JSR# 339
- JAX-RS 1.0: JSRs: Java Specification Requests - detail JSR# 311
JAX-RS 2.0 の仕様に書いている目標 (1.3 Goals) を簡単に紹介すると次のようなものがあります。
- POJO-based: API はアノテーションの集合とそれに関連しており POJO と一緒に使えるようなクラスとインターフェイスを提供する *1。
- HTTP-centric: HTTP は基礎的なネットワークプロトコルであると考えており、JAX-RS は HTTP および URI 要素とそれに対応する API クラスとアノテーションとのマップを提供する。
- Format independence: 様々な HTTP エンティティボディコンテントの種類に対応する。
- Container independence: 様々な種類の web 層のコンテナにデプロイ可能である。 サーブレットコンテナや JAX-WS プロバイダへのデプロイ方法を定義する
- Inclusion in Java EE: The specification will define the environment for a Web resource class hosted in a Java EE container and will specify how to use Java EE features and components within a Web resource class
つまり、原則的には JAX-RS で定義されているアノテーションなどを使って JAX-RS アプリケーションを書くことになります。 そして、JAX-RS に対応した HTTP サーバーやサーブレットコンテナでそのアプリケーションを実行させることができるわけです。 JAX-RS アプリケーションは (理想的には) サーバーの実装に依存しないので、移植性が高くなります。
Ruby や Perl でも Rack や PSGI といった仕様が定義されていますが、大体そんな感じです *2
本記事ではサーバーサイドの話のみを記述しますが、JAX-RS 2.0 ではクライアントサイド用の API も定義されました。
「Hello world!」 を返すシンプルな JAX-RS アプリケーション
Servlet コンテナで実行される JAX-RS アプリケーションを単純に実装すると上のコミットのような感じになります。 JAX-RS アプリケーションとして重要な部分は、次の 2 つのクラスです。
Root
クラス: 「Hello world!」 を表すリソースクラス。 ルートパスに対応することをアノテーションで示している。 このようにアノテーションによって特定の URI と対応付けられたクラスを JAX-RS ではリソースクラスと呼ぶ。MyApplication
クラス: アプリケーションの設定等を含むクラス。 このgetClasses
メソッドの返り値に含まれるクラスがリソースクラスとして使われる。 *3
上のコミットでは、どちらのクラスも JAX-RS 仕様に含まれるアノテーションやクラスのみを使用しています。
最近の Servlet 仕様では、ある条件下において web.xml デプロイメント記述子を省略できるらしくて *4、JAX-RS アプリケーションを Servlet コンテナで実行させる場合も特定条件下では web.xml を省略できます。
例えば、上のコミットの例のように、Application
クラス のサブクラスが含まれていて、そのクラスに @ApplicationPath
アノテーション が付けられている場合で、Servlet 3 framework pluggability mechanism が使われるコンテナで使用する場合は web.xml を省略できます *5。 よって、上のコミットの内容で WAR ファイルを作って GlassFish サーバーなどにデプロイすれば JAX-RS アプリケーションが動くはずです。
JAX-RS 実装 Jersey
JAX-RS アプリケーションを動作させるための実装の 1 つに Jersey があります。 Jersey は JAX-RS の参照実装でもあります。
Jersey は アプリケーションサーバー GlassFish の中に組み込まれているので、GlassFish 上で JAX-RS アプリケーションを動かす場合には Jersey を使用することになるでしょう。 また、Jersey は JAX-RS アプリケーションを実行することのできる Servlet 実装も提供しているので、Jersey が提供している Servlet に JAX-RS アプリケーションをラップさせて、任意の Servlet コンテナで JAX-RS アプリケーションを実行するということもできます。
また、単に JAX-RS アプリケーションを動かす側の実装だけでなく、JAX-RS アプリケーションを実装するために便利な API を提供してくれたりもします。 今回のサンプルプロジェクトでも Jersey の便利な機能を使っているので、この下で紹介します。
Jersey を使って Application
のサブクラスをより簡易に実装する
Jersey には ResourceConfig
という Application
クラス のサブクラスが含まれています。
これを使用することで、例えば getClasses
メソッドを自分で実装する必要がなくなったりします。 今回のサンプルプロジェクトでは、packages
メソッドを使ってリソースクラスが入っているパッケージ名を指定し、リソースクラスをスキャニングさせるように変更しました。
Servlet 3.x コンテナの中で Jersey アプリケーションを動かす
上で書いたように、GlassFish などの一部のサーブレットコンテナでは明示的な Servlet の指定をしなくても JAX-RS アプリケーションを認識してくれるっぽいのですが、web.xml にちゃんと Servlet を明示しないとだめな Servlet 3.x コンテナもあるようです。 (Jetty 9 で試したところ web.xml に Servlet を明示しないと動いてくれませんでした。 が、web 上を見てたら Jetty 9 でも web.xml 不要とか書いてる記事もあるので私の使い方がおかしいのかも。)
今回の例では、Jersey が提供する ServletContainer
*6 を使って、任意の Servlet 3.x コンテナにデプロイできるようにしました。
Servlet 3.x コンテナ用のサーバー側実装だけでなく、Servlet 2.x コンテナ用の実装など、他の JAX-RS アプリケーションコンテナの実装もあります。
開発環境の話
ここまでは特に IDE には依存しないような感じで書いてきましたが、実際の開発では IDE を使うことになると思います。 Web 上で調べてみたところお、JAX-RS アプリケーションを書くなら NetBeans 一択というような感じがしました。 実際、自分でも Eclipse や NetBeans、IntelliJ を試してみましたが、JAX-RS アプリケーションを書くなら NetBeans が使いやすいように感じました。
NetBeans を使う場合は開発用のサーバーは GlassFish が標準なので、GlassFish を使うことになると思います。 NetBeans + GlassFish の開発環境を準備する話は次の記事が参考になりました。
NetBeans で JAX-RS に従った web アプリケーションを作る方法については次のチュートリアルが参考になります。
しかし、Gradle や Maven を使ってるプロジェクトを NetBeans にインポートするとき、プロジェクト管理をそのまま Gradle や Maven を使って行うのは難しいっぽい感じがしますね。 IDE によるプロジェクト管理と IDE に依存しないプロジェクト管理をどうするか、みたいなの悩ましい感じがします。
まとめ
単に 「Hello world!」 を返すような web アプリケーションを例に、JAX-RS アプリケーションの基本的な作成方法を説明しました。 今回は次のようなものを使いました。
- JAX-RS アプリケーションの実装に Jersey が提供している JAX-RS アプリケーション用の便利機能を使った
- JAX-RS アプリケーションを Servlet 3.x コンテナで実行するために、Jersey が提供している Servlet 実装を使った
- JAX-RS アプリケーションを WAR に固めるために Gradle の war プラグインを使った
- JAX-RS アプリケーションを開発時に簡単に動かせるように Gradle の jetty プラグインを使った
一口に JAX-RS アプリケーションといっても、どのサーバーで動かすかなどによって作法が変わってくるところもあるのでどうすればいいのか結構悩んでいたのですが、今のところ IDE に依存しない感じでプロジェクトを作るなら上のような感じが良さそうだなーと思っています。
参考文献
JAX-RS の基本的なことを知るなら次の本がオススメです。
- 作者: Bill Burke,arton,菅野良二
- 出版社/メーカー: オライリージャパン
- 発売日: 2010/08/23
- メディア: 大型本
- 購入: 28人 クリック: 804回
- この商品を含むブログ (40件) を見る
あとは次のような記事が参考になります。
- JAX-RSとかの話 — 裏紙 : Java EE 周りをある程度理解している人なら JAX-RS のとっかかりとしてこの記事がわかりやすいと思います。 本記事のサンプルコードでは Jersey 2.4 を使っていますが、この記事では Jersey 1 系が使われていることには注意が必要です。 (Jersey のパッケージ名が違うしコピペして動かない可能性がある)
[Java] Jetty9(Servlet3.0)でJAX-RS | ルクサエンジニアのブログ : Jetty 9 (Servlet 3.x) で JAX-RS アプリケーションを動かすという記事。 ちょっと参考にしたので参考文献として挙げましたが、間違ってる部分もあるということで削除しておきます。 詳しくは本記事のコメント参照。- JAX-RS実装のデプロイメントについて | OPENSQUARE.jp - BLOG : JAX-RS アプリケーションのデプロイに web.xml デプロイメント記述子は省略できるのかどうか、ということを試している記事。 「基本的に web.xml は必要」 という結論っぽいけど、必ずしも web.xml が必要というわけではないので注意が必要。 これに関してもコメント頂いたので、本記事のコメントの方がご覧ください。
- eXtreme JAX-RS : HTTP と JAX-RS の関係といった基礎的なことから、デプロイ方法についてや JAX-RS における認証・認可についての話などが書かれたスライド。 わかりやすいです。
- JAX-RS 2.0 ことはじめ - Programming Studio : JAX-RS 2.0 仕様についての概観。 上のスライドの方がオススメだと著者の Hasunuma さんからコメント頂きました。
*1:つまり、POJO (= 通常の Java クラス) としてリソースを表すクラスを定義できる
*2:厳密にいうと JAX-RS は HTTP リクエストやレスポンスそのものには触らないようになっているので、Rack や PSGI と比べると少し高度ではあります。
*3:Application
のサブクラスがアーカイブファイルに含まれていない場合や、getClasses
が空の Set
を返す場合にはアーカイブファイル内のリソースファイルを全て検索されたりするが、ここでは説明しない。
*4:詳しいことは知らない。
*5:JAX-RS 2.0 仕様を読むとそんな風に読み取れるけど違うかもしれない。
*6:ServletContainer
という名前ですが、Servlet コンテナではなくて JAX-RS アプリケーションのコンテナの役割をする Servlet です。