LoginSignup
2
2

More than 5 years have passed since last update.

JAX-RS の WebTarget.queryParam() の落とし穴

Last updated at Posted at 2018-03-11

JAX-RS Client の WebTarget.queryParam() の仕様にハマったのでメモ。

問題点

WebTarget.queryParam() の仕様はこちらです。
WebTarget に対してクエリパラメータを設定するというメソッドです。

このメソッド、URIエンコードについて注意点があります。

  • パラメータ名・値ともに URIテンプレートが使用できる。
  • 仕様には明記されていないが、たいていの実装ではパラメータ名・値ともに URI エンコードしてくれる。

URIテンプレートは {} で囲んだ部分にパスパラメータを突っ込んでくれるという機能ですが、よく考えるとちょっと問題があります。
それはクエリパラメータ値に "{" や "}" 自体を含めることができない、という問題です。"{", "}" ともにパスパラメータとして解釈されるためですね。

これを避けるためには、"{" や "}" を URIエンコードしなければなりません。それぞれ %7b, %7d にすれば良いということです。

が、JerseyやRESTEasyなどの実装では本メソッドは上記の通り URI エンコードをする動作なので、そのままもう一度URIエンコードされると %257b, %257d に変換されてしまうはずです。つまり { や } が使えないのでは、、、?

回避方法

Jersey 実装ではこれを回避するために URI エンコードを二重に実施しないようになっています。具体的には % の後ろに16進文字(0-9a-fA-F)が2個連続している場合は % をエンコードしないというルールです。なので、{, } をそのままエンコードしても大丈夫です。

また逆に考えると、たまたま % の後ろに16進文字が2個連続していたら % は URL エンコードしてくれないということでもあります。

従って、常に自分で URIエンコードしてから queryParam() を呼ぶようにしたほうがよいということです。

他の実装がどうなっているかは知りません。RESTEasy のコードをちょっと見た感じでは % は一切エンコードしないようになっていたみたいです。

当然ですが、上記動作は JAX-RS の仕様からは読み取れないです(実装依存)。なので一応動作確認してから使いましょう。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2