これが明示的に言及されているようには見えませんが、クエリ引数が java.net.URI を使用している場合、エスケープされたプラス記号 ("%2b") をクエリ引数値として送信できないようです。エスケープされます。
// bad: http://example.com/foo?a=%252b
new URI("http", null, "example.com", 80, "/foo", "a=%2b", null);
実際の「+」文字を試してみましたが、そのまま送信されるため、サーバーはスペースとして解釈します。
// bad: http://example.com/foo?a=+
new URI("http", null, "example.com", 80, "/foo", "a=+", null);
ですから、クエリ引数のキーと値のパーセント エンコーディングを自分で行い、エスケープしない単一引数の URI コンストラクタを使用するだけでよいのではないでしょうか。ルールがトリッキーなので、おそらく URI は「パス」をエスケープさせます (たとえば、「+」文字は、パスにある場合、スペースではなくプラス文字を意味します)。
// good: http://example.com/foo?a=%2b
new URI(new URI("http", null, "example.com", 80, "/foo", null, null).toASCIIString() + "?a=%2b");
また、ドキュメントでは、次のような URI を作成できると主張しており、ソース URI と同じになります。
URI u = ...;
URI identical = new URI(u.getScheme(),
u.getUserInfo(),
u.getPath(), u.getQuery(),
u.getFragment());
%2b が含まれている場合は当てはまりません
URI u = new URI("http://example.com:80/foo?a=%2b");
URI identical = ...; // not identical! http://example.com:80/foo?a=+
イライラする、それが誰もが代わりにApache CommonsまたはSpring Classを使用する理由だと思いますか?
PS: http://docs.oracle.com/javase/6/docs/api/java/net/URI.htmlは、「次の ID も保持されます」セクションに存在しない URI コンストラクターを参照しています。「権限」パラメーターを削除する必要があります。