1. 序章

前の記事では、 JAX-RS2.0RESTEasyサーバー側実装に焦点を当てました。

JAX-RS 2.0 では、新しいクライアントAPIが導入されているため、リモートのRESTfulWebサービスにHTTPリクエストを送信できます。 Jersey、Apache CXF、Restlet、およびRESTEasyは、最も一般的な実装のサブセットにすぎません。

この記事では、 RESTEasy API を使用してリクエストを送信することにより、 RESTAPIを使用する方法について説明します。

2. プロジェクトの設定

pom.xmlに次の依存関係を追加します。

<properties>
    <resteasy.version>4.7.2.Final</resteasy.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-client</artifactId>
        <version>${resteasy.version}</version>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
    </dependency>
    ...
</dependencies>

3. クライアント側のコード

クライアントの実装は非常に小さく、3つの主要なクラスで構成されています。

    • クライアント
    • WebTarget
    • 応答

Client インターフェースは、WebTargetインスタンスのビルダーです。

WebTarget は、より多くのサブリソースWebTargetを構築したり、リクエストを呼び出したりできる、個別のURLまたはURLテンプレートを表します。

クライアントを作成するには、実際には2つの方法があります。

  • 標準的な方法は、org.jboss.resteasy.client.ClientRequestを使用することです。
  • RESTeasyプロキシフレームワークResteasyClientBuilderクラスを使用する

ここでは、RESTEasyプロキシフレームワークに焦点を当てます。

JAX-RSアノテーションを使用して着信リクエストをRESTFulWebサービスメソッドにマッピングする代わりに、クライアントフレームワークはリモートRESTfulWebサービスで呼び出すために使用するHTTPリクエストを構築します。

それでは、Javaインターフェースの作成を開始し、メソッドとインターフェースでJAX-RSアノテーションを使用してみましょう。

3.1. ServicesClientインターフェイス

@Path("/movies")
public interface ServicesInterface {

    @GET
    @Path("/getinfo")
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    Movie movieByImdbId(@QueryParam("imdbId") String imdbId);

    @POST
    @Path("/addmovie")
    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    Response addMovie(Movie movie);

    @PUT
    @Path("/updatemovie")
    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    Response updateMovie(Movie movie);

    @DELETE
    @Path("/deletemovie")
    Response deleteMovie(@QueryParam("imdbId") String imdbId);
}

3.2. 映画教室

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "movie", propOrder = { "imdbId", "title" })
public class Movie {

    protected String imdbId;
    protected String title;

    // getters and setters
}

3.3. リクエストの作成

ここで、APIを使用するために使用できるプロキシクライアントを生成します。

String transformerImdbId = "tt0418279";
Movie transformerMovie = new Movie("tt0418279", "Transformer 2");
UriBuilder FULL_PATH = UriBuilder.fromPath("http://127.0.0.1:8082/resteasy/rest");
 
ResteasyClient client = (ResteasyClient)ClientBuilder.newClient();
ResteasyWebTarget target = client.target(FULL_PATH);
ServicesInterface proxy = target.proxy(ServicesInterface.class);

// POST
Response moviesResponse = proxy.addMovie(transformerMovie);
System.out.println("HTTP code: " + moviesResponse.getStatus());
moviesResponse.close();

// GET
Movie movies = proxy.movieByImdbId(transformerImdbId);

// PUT
transformerMovie.setTitle("Transformer 4");
moviesResponse = proxy.updateMovie(transformerMovie);
moviesResponse.close();

// DELETE
moviesResponse = proxy.deleteMovie(batmanMovie.getImdbId());
moviesResponse.close();

RESTEasyクライアントAPIはApacheHttpClientに基づいていることに注意してください。

また、各操作の後、新しい操作を実行する前に応答を閉じる必要があることにも注意してください。 これが必要なのは、デフォルトでは、クライアントで使用できるHTTP接続は1つだけだからです。

最後に、DTOを直接操作していることに注意してください。JSONまたはXMLとの間のマーシャル/アンマーシャルロジックは処理していません。 これは、JAXBまたはJacksonを使用して舞台裏で発生します。これは、Movieクラスに適切な注釈が付けられているためです

3.4. 接続プールを使用したリクエストの作成

前の例の1つの注意点は、使用可能な接続は1つだけであるということです。 たとえば、次のことを実行しようとします。

Response batmanResponse = proxy.addMovie(batmanMovie);
Response transformerResponse = proxy.addMovie(transformerMovie);

batmanResponseclose()を呼び出さない場合–2行目が実行されると例外がスローされます。

java.lang.IllegalStateException:
Invalid use of BasicClientConnManager: connection still allocated.
Make sure to release the connection before allocating another one.

繰り返しますが、これは、RESTEasyで使用されるデフォルトのHttpClientorg.apache.http.impl.conn.SingleClientConnManagerであるために発生します。もちろん、これにより、単一の接続のみが使用可能になります。

ここで、この制限を回避するには、 RestEasyClient インスタンスを別の方法で作成する必要があります(接続プールを使用)。

PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build();
cm.setMaxTotal(200); // Increase max total connection to 200
cm.setDefaultMaxPerRoute(20); // Increase default max connection per route to 20
ApacheHttpClient43Engine engine = new ApacheHttpClient43Engine(httpClient);

ResteasyClient client = ((ResteasyClientBuilder) ClientBuilder.newBuilder()).httpEngine(engine).build();
ResteasyWebTarget target = client.target(FULL_PATH);
ServicesInterface proxy = target.proxy(ServicesInterface.class);

これで、適切な接続プールを利用でき、毎回接続を解放しなくても、クライアントを介して複数のリクエストを実行できます。

4. 結論

このクイックチュートリアルでは、 RESTEasyプロキシフレームワークを紹介し、それを使用して非常にシンプルなクライアントAPIを構築しました。

このフレームワークは、クライアントを構成するためのさらにいくつかのヘルパーメソッドを提供し、JAX-RSサーバー側の仕様の反対のミラーとして定義できます。

この記事で使用されている例は、GitHubサンプルプロジェクトとして入手できます。