Spring MVC+RestTemplateで配列JSONをJavaBeanの配列又はListに変換する

[前回](http://qiita.com/kazuki43zoo/items/7d294c3e3500c9855c10)は、Jackson単体で「配列JSONをJavaBeanの配列又はListに変換する方法」を紹介しました。今回は、Spring MVCとSpring Webから提供されている`RestTemplate`で「配列JSONをJavaBeanの配列又はListに変換する方法」を紹介したいと思います。

前回と同様に、以下のようなJSONをJavaBean(`Todo`)の配列やリストにマッピングします。

* 配列JSON

```json
[
  {
    "title" : "Jsckson勉強会"
  }
  ,
  {
    "title" : "飲み会"
  }
]
```

* JavaBean(`Todo`)

```java
public class Todo {
    private String title;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}
```

# 動作検証バージョン

* Spring Boot 1.3.6.RELEASE
* Spring Framework 4.2.7.RELEASE
* Jackson 2.6.7

# 検証コード

* https://github.com/kazuki43zoo/qiita-materials/tree/master/spring-mvc/json-demo

# Spring MVCで配列JSONを読み込む

リクエストBODYに設定された配列JSONを、Spring MVCのHandlerメソッドの引数（JavaBeanのリスト）として受け取り方法をみていきましょう。
Handlerメソッドの引数として受け取り場合は、引数の型を`List<T>`とし、引数に`@org.springframework.web.bind.annotation.RequestBody`するだけで実現できます :smile: 

```java

@RequestMapping(path = "/api/v1/todos", method = RequestMethod.POST)
public List<Todo> post(@RequestBody List<Todo> todos) {
    return todos;
}
```

# `RestTemplate`で配列JSONを読み込む

実際に`RestTemplate`経由でSpring MVCのHandlerメソッドを呼び出してみます。なお、Junitで作っていますが、今回はAssertは省略させてもらいます。

```java
package com.example;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.WebIntegrationTest;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = JsonDemoApplication.class)
@WebIntegrationTest(randomPort = true)
public class SpringWebMvcJsonArrayTests {

    @Value("http://localhost:${local.server.port}/api/v1/todos")
    private URI uri;

    private final RestTemplate restTemplate = new RestTemplate();

    private final List<Todo> requestTodoList = Arrays.asList(
            new Todo("Jsckson勉強会")
            , new Todo("飲み会")
    );

    /**
     * 配列として読み込む
     */
    @Test
    public void array() throws IOException {

        Todo[] todoArray = restTemplate.postForObject(uri, requestTodoList, Todo[].class);
        for (Todo todo : todoArray) {
            System.out.println(todo.getTitle());
        }

    }

    /**
     * 配列として読み込みArrays#asListでリスト化する
     */
    @Test
    public void arrayConvertListUsingArraysAsList() {

        List<Todo> todoList = Arrays.asList(restTemplate.postForObject(uri, requestTodoList, Todo[].class));
        for (Todo todo : todoList) {
            System.out.println(todo.getTitle());
        }

    }

    /**
     * ParameterizedTypeReferenceを使用してリストとして読み込む
     */
    @Test
    public void listUsingParameterizedTypeReference() {
        RequestEntity<List<Todo>> requestEntity = RequestEntity.post(uri).body(requestTodoList);
        ResponseEntity<List<Todo>> responseEntity = restTemplate.exchange(requestEntity, new ParameterizedTypeReference<List<Todo>>() {});
        for (Todo todo : responseEntity.getBody()) {
            System.out.println(todo.getTitle());
        }
    }

}
```

## 配列として読み込む

一番シンプルな読み込み方法です。メソッド内の処理だけで使う＋拡張For文などで単純な繰り返し処理を行うだけなら配列でもよいと思います。

```java
Todo[] todoArray = restTemplate.postForObject(uri, requestTodoList, Todo[].class);
```

## 配列として読み込み`Arrays#asList`でリスト化する

読み込んだ配列をメソッドの返り値として返却するような場合は、配列ではなくリストを使うのが一般的でしょう。そんな時は、`java.util.Arrays#asList(T...)`を使うと簡単にリスト化できます。なお、この方法でリスト化すると、リストに対して要素の追加や削除などができないリストが生成されます。（要素を追加、削除すると`java.lang.UnsupportedOperationException`が発生します）

```java
List<Todo> todoList = Arrays.asList(restTemplate.postForObject(uri, requestTodoList, Todo[].class));
```

## `ParameterizedTypeReference`を使用してリストとして読み込む

リストとして読み込む方法もあります。リストとして読み込む場合は、読み込みたい型を`org.springframework.core.ParameterizedTypeReference`の型パラメータに指定します。この方法で生成したリストに対しては、要素の追加や削除もできます。

```java
ResponseEntity<List<Todo>> responseEntity =
    restTemplate.exchange(requestEntity, new ParameterizedTypeReference<List<Todo>>() {});
```

# まとめ
Spring MVCの方はHandlerメソッドの引数にリストを宣言するだけなので非常にGoodです :+1:
`RestTemplate`の方は、前回紹介した(Jackson単体での実装方法)とほとんど同じですね。やっぱり`ParameterizedTypeReference`(`TypeReference`)はあまり好きになれないな〜 :sweat_smile: