1. 概要

私たちのサービスは、情報を取得するために他のRESTサービスと通信する必要があることがよくあります。

Springでは、RestTemplateを使用して同期HTTP要求を実行できます。 データは通常JSONとして返され、RestTemplateで変換できます。

このチュートリアルでは、JSON配列をJavaで3つの異なるオブジェクト構造に変換する方法を探ります。ObjectArrayArrayです。 POJOおよびPOJOのリスト

2. JSON、POJO、およびサービス

エンドポイントがあると想像してみましょう http://localhost:8080/users ユーザーのリストを次のJSONとして返します。

[{
  "id": 1,
  "name": "user1",
}, {
  "id": 2,
  "name": "user2"
}]

データを処理するには、対応するUserクラスが必要です。

public class User {
    private int id;
    private String name;

    // getters and setters..
}

インターフェイスの実装では、依存関係としてRestTemplateを使用してUserConsumerServiceImplを記述します。

public class UserConsumerServiceImpl implements UserConsumerService {

    private final RestTemplate restTemplate;

    public UserConsumerServiceImpl(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

...
}

3. JSONオブジェクトのリストのマッピング

RESTリクエストへの応答がJSON配列である場合、それをJavaコレクションに変換する方法はいくつかあります。 オプションを見て、返されたデータをどれだけ簡単に処理できるかを見てみましょう。 RESTサービスによって返されるいくつかのユーザーオブジェクトのユーザー名を抽出する方法を見ていきます。

3.1. RestTemplateとオブジェクト配列

まず、 RestTemplate.getForEntity を使用して呼び出しを行い、タイプ Object[]ResponseEntityを使用して応答を収集します。

ResponseEntity<Object[]> responseEntity =
   restTemplate.getForEntity(BASE_URL, Object[].class);

次に、ボディをObjectの配列に抽出できます。

Object[] objects = responseEntity.getBody();

ここでの実際のObjectは、データを含むがUserタイプを使用しない任意の構造です。 それをUserオブジェクトに変換してみましょう。

このためには、ObjectMapperが必要です。

ObjectMapper mapper = new ObjectMapper();

インラインで宣言できますが、これは通常、クラスの private staticfinalメンバーとして行われます。

最後に、ユーザー名を抽出する準備ができました。

return Arrays.stream(objects)
  .map(object -> mapper.convertValue(object, User.class))
  .map(User::getName)
  .collect(Collectors.toList());

このメソッドを使用すると、基本的にanythingの配列をJavaのObject配列に読み込むことができます。 これは、たとえば、結果のみをカウントしたい場合に便利です。 ただし、それ以上の処理には適していません。 私たちはそれを私たちが扱えるタイプに変換するために余分な努力をしなければなりませんでした。

Jackson Deserializerは、ターゲットタイプとして Object を生成するように要求すると、実際にJSONを一連のLinkedHashMapオブジェクトに逆シリアル化します。 convertValue による後処理は、非効率的なオーバーヘッドです。

そもそもジャクソンに希望のタイプを提供すれば回避できます。

3.2. RestTemplateとユーザーアレイ

Object [] の代わりに、 User[]RestTemplateに提供できます。

  ResponseEntity<User[]> responseEntity = 
    restTemplate.getForEntity(BASE_URL, User[].class); 
  User[] userArray = responseEntity.getBody();
  return Arrays.stream(userArray) 
    .map(User::getName) 
    .collect(Collectors.toList());

ObjectMapper.convertValueが不要になっていることがわかります。 ResponseEntity には、Userオブジェクトが含まれています。 ただし、Java Stream APIを使用し、コードをリストで機能させるには、さらにいくつかの変換を行う必要があります。

3.3. RestTemplateとユーザーリストおよびParameterizedTypeReference

ジャクソンが配列の代わりにユーザーリストを生成する便利さが必要な場合は、作成するリストを記述する必要があります。 これを行うには、RestTemplate。exchangeを使用する必要があります。 このメソッドは、匿名内部クラスによって生成されたParameterizedTypeReferenceを取ります。

ResponseEntity<List<User>> responseEntity = 
  restTemplate.exchange(
    BASE_URL,
    HttpMethod.GET,
    null,
    new ParameterizedTypeReference<List<User>>() {}
  );
List<User> users = responseEntity.getBody();
return users.stream()
  .map(User::getName)
  .collect(Collectors.toList());

これにより、使用するリストが生成されます。

ParameterisedTypeReferenceを使用する必要がある理由を詳しく見てみましょう。

最初の2つの例では、SpringはJSONを User.class タイプトークンに簡単に逆シリアル化でき、実行時にタイプ情報が完全に利用可能になります。

ただし、ジェネリックスでは、使用しようとすると型消去が発生しますリスト 。クラス 。 したがって、ジャクソンは内部のタイプを判別できません。 <>

と呼ばれるスーパータイプトークンを使用することでこれを克服できます ParameterizedTypeReference。 匿名の内部クラスとしてインスタンス化– 新しいParameterizedTypeReference >(){} –ジェネリッククラスのサブクラスには、型消去の対象ではなく、リフレクションを通じて使用できるコンパイル時の型情報が含まれているという事実を利用します。

4. 概要

この記事では、JSONオブジェクトを使用してJSONオブジェクトを処理する3つの異なる方法を見ました RestTemplate。 の配列の種類を指定する方法を見ました物体そして私たち自身のカスタムクラス。

次に、 ParameterizedTypeReference を使用して、Listを生成するための型情報を提供する方法を学びました。

いつものように、この記事のコードはGitHubから入手できます。