RestTemplateを使ってオブジェクトのリストを取得および投稿する

1.はじめに

RestTemplate クラスは、SpringでクライアントサイドのHTTP操作を実行するための中心的なツールです。 HTTPリクエストを構築し、レスポンスを処理するためのユーティリティメソッドがいくつかあります。

そして、 RestTemplate はhttps://github.com/FasterXML/jackson[Jackson]とうまく統合されているので、ほとんどのオブジェクトをJSONとの間でシリアライズ/デシリアライズすることができます。

しかし、 オブジェクトのコレクションを扱うことはそれほど簡単ではありません

このチュートリアルでは、 RestTemplate GET POST の両方のオブジェクトのリストに使用する方法を説明します。

2.サービス例

2つのHTTPエンドポイントを持つ従業員APIを使用します - すべて取得して作成します。

  • GET/従業員

  • POST/employees

クライアントとサーバー間の通信には、単純なDTOを使用して基本的な従業員データをカプセル化します。

public class Employee {
    public long id;
    public String title;

   //standard constructor and setters/getters
}

これで、 RestTemplate を使用して Employee オブジェクトのリストを取得および作成するコードを作成する準備が整いました。

3. RestTemplate を使ってオブジェクトのリストを取得する

通常、GETを呼び出すときは、 RestTemplate の中の____:などの単純化されたメソッドを使用できます。

getForObject(URI、クラス<T> responseType)

これは、GET動詞を使用して指定されたURIに要求を送信し、応答本体を要求されたJavaタイプに変換します。これはほとんどのクラスでうまく機能しますが、制限があります。** オブジェクトのリストを送信することはできません。

この問題は、Javaジェネリックの型消去によるものです。アプリケーションが実行されているときは、どの種類のオブジェクトがリストに含まれているのかがわかりません。これは、リスト内のデータを適切な型に逆シリアル化できないことを意味します。

幸い、これを回避するには2つの方法があります。

3.1. ParameterizedTypeReference を使用する

ResponseEntity ParameterizedTypeReference の組み合わせを使用すると、 RestTemplate を使用してオブジェクトのリストを簡単に取得できます。

RestTemplate restTemplate = new RestTemplate();
ResponseEntity<List<Employee>> response = restTemplate.exchange(
  "http://localhost:8080/employees/",
  HttpMethod.GET,
  null,
  new ParameterizedTypeReference<List<Employee>>(){});
List<Employee> employees = response.getBody();

上記のコードでは、いくつかのことが起こります。まず、戻り値の型として ResponseEntity を使用し、それを使用して実際に必要なオブジェクトのリストをラップします。次に、 getForObject() ではなく RestTemplate.exchange() を呼び出しています。

これが RestTemplate を使用する最も一般的な方法です。 HTTPメソッド、オプションのリクエストボディ、そしてレスポンスタイプを指定する必要があります。この場合、レスポンスタイプに ParameterizedTypeReference の無名サブクラスを使用します。

この最後の部分で、JSONレスポンスを適切なタイプのオブジェクトのリストに変換できます。 ParameterizedTypeReference の匿名サブクラスを作成すると、リフレクションを使用してレスポンスの変換先となるクラスタイプに関する情報を取得します。

Javaの Type オブジェクトを使用してこの情報を保持しているので、型の消去について心配する必要はもうありません。

このアプローチの利点は、既存のコードをすべて使用できるということです。

私たちのEmployeeオブジェクトは、アプリケーションのエンドポイントと同様に、そのまま機能します。欠点は、コードがもう少し冗長であることです。

3.2. ラッパークラスの使い方

一部のAPIは、リストを直接返すのではなく、従業員のリストを含む最上位オブジェクトを返します。この状況に対処するために、従業員のリストを含むラッパークラスを使用できます。

public class EmployeeList {
    private List<Employee> employees;

    public EmployeeList() {
        employees = new ArrayList<>();
    }

   //standard constructor and getter/setter
}

これで、より単純な getForObject() メソッドを使用して従業員のリストを取得できます。

EmployeeList response = restTemplate.getForObject(
  "http://localhost:8080/employees",
  EmployeeList.class);
List<Employee> employees = response.getEmployees();

このコードははるかに単純ですが、追加のラッパーオブジェクトが必要です。

4. RestTemplate を使ってオブジェクトのリストを投稿する

それでは、クライアントからサーバーにオブジェクトのリストを送信する方法を見てみましょう。上記のように、 RestTemplate はPOSTを呼び出すための単純化されたメソッドを提供します。

postForObject(URI、オブジェクト要求、クラス<T>応答タイプ)

これはHTTP POSTを与えられたURIに、オプションのリクエストボディと共に送信し、そしてレスポンスを指定されたタイプに変換します。上記のGETシナリオとは異なり、 型の消去について心配する必要はありません

これは、現在、JavaオブジェクトからJSONに移行しているためです。オブジェクトのリストとそのタイプはJVMによって認識されているため、正しくシリアル化されます。

List<Employee> newEmployees = new ArrayList<>();
newEmployees.add(new Employee(3, "Intern"));
newEmployees.add(new Employee(4, "CEO"));

restTemplate.postForObject(
  "http://localhost:8080/employees/",
  newEmployees,
  ResponseEntity.class);

4.1. ラッパークラスの使い方

上記のGETシナリオと一致させるためにラッパークラスを使用する必要がある場合は、それも簡単です。 RestTemplate を使用して新しいリストを送信できます。

List<Employee> newEmployees = new ArrayList<>();
newEmployees.add(new Employee(3, "Intern"));
newEmployees.add(new Employee(4, "CEO"));

restTemplate.postForObject(
  "http://localhost:8080/employees",
  new EmployeeList(newEmployees),
  ResponseEntity.class);

5.まとめ

RestTemplateを使用することはあなたのサービスと通信するためにHTTPクライアントを構築する簡単な方法です。

それはあらゆるHTTPメソッドと単純なオブジェクトを扱うための多くのメソッドを提供します。少し余分なコードを追加すれば、簡単にそれを使ってオブジェクトのリストを処理することができます。

いつものように、完全なコードはhttps://github.com/eugenp/tutorials/tree/master/spring-rest[Githubプロジェクト]にあります。