はじめに
RESTful API を実装しようと思い調べたが、古い情報が多かったので
少し新しい情報として書いておく。
目的
- RESTful APIは処理がシンプルなので構築環境もなるべく簡潔で解り易いものが良い
- 開発ツールは Eclipse を使う
- JAX-RSの仕様の実装として Jersey を使う
- WEBサーバーは Tomcat を使う
J2EE のサーバーである必要は無く、Springとかのフレームワークも使わない。
Eclipse で Jersey を使う
RESTful をサービスを提供する為に Java では JAX-RS という仕様がある。
その実装は Apache CXF 等いくつかあるが、その中で Jersey を使うことにした。
理由は特になく、使用例を多く見かけたので利用者も多いと考えた。
Eclipseについては説明するまでもないと思うが、Pleiades のものを使う。
まずプロジェクトを新規で作る。
ここでは「mavenプロジェクト」で作成する。
その中で、アーキタイプを選択する。一種の雛型である。
沢山表示されるので、フィルターで、「glassfish.jersey」と入力すれば絞れる。
「jersey-quickstart-webapp」を選択する。
最新バージョンしか表示されていないが、チェックを外すと過去のバージョンも選択できる。
後で詳しく述べるがバージョンの選択は重要。
少なくとも、ここで選択したのは Tomcat10 以上を使う場合である。
グループId、アーティファクトId を入力する。とりあえず名前は何でも良いが、後者が Eclipse のプロジェクト名にもなる。
「完了」でプロジェクトが作成される。
これは何を行うプロジェクトか?
jersey-quickstart-webapp アーティファクトは Jersey の環境と簡単なサンプルを内包している。
このサンプルは、実行するとブラウザが立ち上がり以下の様なWEBページが表示される。
リンクをクリックして「Got it!」が表示されれば環境構築が正常に出来ていることになる。
こう説明してしまうと簡単なようだが、実際にはうまくいかない場合がある。
下が実際のエラーの例
多くは、「コンソール」窓(ビュー)の横にある「問題」(もしくは「マーカー」と表示)のエラーの説明で解る。
- プロジェクトに✖印が付いて他にエラー箇所が無い
- JSPに✖が付いている
- web.xmlに✖が付いている
プロジェクトだけに✖印が付いている場合、プロジェクトを一度「クリーン」してみる。
「Java プロジェクト・ファセットのバージョンと一致しません。」のようなエラーなら、ターゲットとなる Tomcatの実行環境の Java のバージョンがコンパイルの Java のバージョンと一致していない。プロジェクトの設定で同じにする。
JSPに✖が付いている、web.xmlの✖は Eclipse の検証機能が正しく働いていない。
古い Eclipse を使っていたら最新版にしてみるのが良い。(2024年版にしたらエラーが消えた)
これらのエラーは無視しても実行できるが、気になるなら、Eclipse の「設定」「検証」で「JSP構文バリデターのビルド」を外す事で対処できるようだ。
実行してみる
「サーバーで実行」を選択し、Eclipseにインストール済の Tomcat を選択する。
ここでは Tomcat10 以上を選択すること。
Jersey3.x以上は Tomcat9 以下では動かない。
Tomcat10 以上が無い場合(Eclipseのバージョンが古い)は追加で Tomcat をインストールする事も出来る。
その際 JREは Apache Tomcat Versions にあるように、Java11 以上で動かす必要がある。
JSPの画面は表示されるが、リンクをクリックしてもエラーになる場合がある。
Tomcat10 を Java11 で動かすと下記の様なエラーがログに見られた。
重大: Web アプリケーション [/jersey40] のサーブレット [Jersey Web Application] の load() メソッドは例外を投げました。 [土 8月 10 18:04:20 JST 2024]
Tomcat10 を Java17 以上で動かすと問題ない。
理由は不明だが、Java11 から Java17 での変更点が影響しているのかも知れない
Tomcat9.0で動かしたい場合
どうしても、実環境が Tomcat9 しか用意出来ない場合、Jersey のバージョンは 2.x で動かすことになる。
この場合、最初のプロジェクトの新規作成で、アーティファクトは古いバージョンを選ぶ。
例えば、jersey 2.5 を選ぶ。
この場合もプロジェクトが正常にビルドできない場合がある。
pom.xml でエラーになる場合。
中で記述されている Maven のバージョンが古い。動くバージョンに書き換える。例えば、
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.4.0</version>
</plugin>
Tomcat9で実行時にエラーが出る場合。
Tomcat9 を Java11 以上で動かしていると起こる。
理由はJAXBExceptionというライブラリが標準ライブラリから除外されたためのようで、
pom.xml で追加するか、Tomcat9 を Java8 で動かすかのどちらかで対処。
前者でこのサンプルは動くが、別のエラーがログに出ているので後者のほうが確実。
MyResource.java でコンパイルエラーが出る場合。
import jakarta.ws.rs.Get のように jakarta が使われるのは Tomcat10 以上を前提にしている。
Tomcat9 では javax.wa.rs.Get のように書き換える。
Tomcat10 から J2EE 関係は jakarta に変更されている。
もともと Tomcat は J2EEサーバーでは無いが、Jersey は J2EE の一部の API を使っているのでこの変更が影響している。
これで終わり?
肝心な点が抜けている。
出来たプロジェクトの中身を見ると、web.xml がある。
JAX-RSの仕様では
- Applicationサブクラス
- リソースクラス
の2つがあり、Applicationサブクラス(とアノテーション)があれば web.xml は必要無いはずである。
Applicationサブクラスは@ApplicationPathアノテーションを使って基底の URI を決める事が出来る。
例えば、MyApplication.java を src/main/java 配下のどこかに作成して
@ApplicationPath("/webapi")
public class MyApplication extends Application {
public Set<Class<?>> getClasses() {
Set<Class<?>> s = new HashSet<Class<?>>();
s.add(MyResource.class);
return s;
}
}
もしくは Jersey 限定で良ければ、もう少し簡単に
ApplicationPath("/webapi")
public class MyApplication extends ResourceConfig {
public MyApplication() {
packages("MyPackage");
}
}
import はEclipseなら候補が出るので適宜追加して欲しい。
クラスやパッケージ名も自分の環境のものを使う。
とすれば、web.xml は不要になる。
ネット上の多くの解説では作成したら不要だから web.xml は削除しろと書いてある場合が多い。
実際に削除したらエラーで動かない。
何故動かないか?
それは、このプロジェクトが Servlet3.0 用に構築されていない からだ。
pom.xml を見てみよう。
ちゃんと書いてある。
<!-- use the following artifactId if you don't need servlet 2.x compatibility -->
今時、servlet2.x を使う事など無い。
指定通りコメントアウトを書き換えれば web.xml が無くても動く。
Servlet2.x 用のモジュールでは Tomcat 起動時に Jersey サーブレットが呼ばれない為、アノテーションが働かないと思われる。
なお、web.xml も残しておくと両方が機能する。URI が重複しなければ混在も可能である。
まとめ
トラブルを避けるには Eclipse はなるべく最新版を使う。
Jersey3.x 以上を使いたければ、Tomcat10 以上を使う必要がある。
Maven のアーティファクトの内容が修正されない間は、pom.xml を Servlet3.0 用に修正する必要がある。