Gsonを使ってみた

#Gsonとは
そのまま[引用](https://github.com/google/gson)します。
>Gson
>Gson is a Java library that can be used to convert Java Objects into their JSON >representation. It can also be used to convert a JSON string to an equivalent Java object. >Gson can work with arbitrary Java objects including pre-existing objects that you do not have >source-code of.

>There are a few open-source projects that can convert Java objects to JSON. However, most of >them require that you place Java annotations in your classes; something that you can not do if >you do not have access to the source-code. Most also do not fully support the use of Java >Generics. Gson considers both of these as very important design goals.

# 実験に使用するサンプル

```Person1.java
import java.util.Date;
public class Person1 {

    private Integer age;
    private String name;
    private String noUse;
    private Date target;

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String noUse() {
        return noUse;
    }

    public void noUse(String noUse) {
        this.noUse = noUse;
    }

    public Date target() {
        return target;
    }

    public void target(Date target) {
        this.target = target;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Person1 [age=");
        builder.append(age);
        builder.append(", name=");
        builder.append(name);
        builder.append(", noUse=");
        builder.append(noUse);
        builder.append(", target=");
        builder.append(target);        
        builder.append("]");
        return builder.toString();
    }

}
```

# まずは独自の型に変換する

```Ex1.java
public class Sample {
    public static void main(String[] args){
        //-----------------------------
        // jsonReaderの実験
        //-----------------------------
        StringBuilder jsonReader = new StringBuilder();
        jsonReader.append("[");
        jsonReader.append(" {\"age\":1,\"name\":\"Gson Taro\",\"target\":\"2020-02-10\"},");
        jsonReader.append(" {\"age\":2,\"name\":\"Gson Taro\",\"target\":\"2020-02-30\"},");
        jsonReader.append(" {\"age\":3,\"name\":\"Gson Taro\",\"target\":\"2020-02-12\"}");
        jsonReader.append("]");

        try {
            Gson gsonReader = new Gson();
            Type listType = new TypeToken<List<Person1>>(){}.getType();
            List<Person1> p1 = gsonReader.fromJson(jsonReader.toString(), listType);

            System.out.println("------------------------------------------->");
            System.out.println("Person1#toString: " + p1);
            System.out.println("------------------------------------------->");
        } catch (Exception e) {
            System.out.println(e.getCause());
            System.out.println("------------------------------------------->");
            if(e.getCause() instanceof NumberFormatException) {
				System.out.println("数値エラー：" + e.getCause().getMessage());
			}else if (e.getCause() instanceof ParseException){ 
				System.out.println("日付入力エラー：" + e.getCause().getMessage());
			}
            System.out.println("------------------------------------------->");
        }
    }
```

## 【成功】
難なく成功です。Gsonに変換してほしい型を渡す部分が肝です。

```
------------------------------------------->
Person1#toString: [Person1 [age=1, name=Gson Taro, noUse=null, target=Mon Feb 10 00:00:00 JST 2020], Person1 [age=2, name=Gson Taro, noUse=null, target=Sun Mar 01 00:00:00 JST 2020], Person1 [age=3, name=Gson Taro, noUse=null, target=Wed Feb 12 00:00:00 JST 2020]]
------------------------------------------->
```

# 次にInteger型へnullを割り当てる実験
## Integer型にしている項目をnullにする

```test.java
        StringBuilder jsonReader = new StringBuilder();
        jsonReader.append("[");
        jsonReader.append(" {\"age\":null,\"name\":\"Gson Taro\",\"target\":\"2020-02-10\"},");
        jsonReader.append(" {\"age\":2,\"name\":\"Gson Taro\",\"target\":\"2020-02-30\"},");
        jsonReader.append(" {\"age\":3,\"name\":\"Gson Taro\",\"target\":\"2020-02-12\"}");
        jsonReader.append("]");
```

## 【成功】
ちなみに受け取る方がint型の場合は「0」になりました

```
------------------------------------------->
Person1#toString: [Person1 [age=null, name=Gson Taro, noUse=null, target=Mon Feb 10 00:00:00 JST 2020], Person1 [age=2, name=Gson Taro, noUse=null, target=Sun Mar 01 00:00:00 JST 2020], Person1 [age=3, name=Gson Taro, noUse=null, target=Wed Feb 12 00:00:00 JST 2020]]
------------------------------------------->
```

# 次にInteger型へ文字列を割り当てる実験

```test.java
        StringBuilder jsonReader = new StringBuilder();
        jsonReader.append("[");
        jsonReader.append(" {\"age\":test,\"name\":\"Gson Taro\",\"target\":\"2020-02-10\"},");
        jsonReader.append(" {\"age\":2,\"name\":\"Gson Taro\",\"target\":\"2020-02-30\"},");
        jsonReader.append(" {\"age\":3,\"name\":\"Gson Taro\",\"target\":\"2020-02-12\"}");
        jsonReader.append("]");
```

## 【失敗】
NumberFormatExceptionが発生します。

# 次はDate型に変換できる形式をチェックします

```test.java
        jsonReader.append("[");
        jsonReader.append(" {\"age\":1,\"name\":\"Gson Taro\",\"target\":\"2020-02-10\"},");
        jsonReader.append(" {\"age\":2,\"name\":\"Gson Taro\",\"target\":\"20200230\"},");
        jsonReader.append(" {\"age\":3,\"name\":\"Gson Taro\",\"target\":\"2020/02/12\"}");
        jsonReader.append("]");
```

## 【失敗】
Gsonはjson上で上の行、左の項目からパースして、
変換に失敗した段階で例外を出します。
今回の実験により「yyyy-MM-dd」「yyyyMMdd」の形式の場合は日付に変換されますが、
「yyyy/MM/dd」の場合は例外が発生します。

```
------------------------------------------->
日付入力エラー：Failed to parse date ["2020/02/12"]: Invalid number: _0
------------------------------------------->
```

# 日付の成功例の実験

```test.java
        StringBuilder jsonReader = new StringBuilder();
        jsonReader.append("[");
        jsonReader.append(" {\"age\":1,\"name\":\"Gson Taro\",\"target\":\"2020-02-10\"},");
        jsonReader.append(" {\"age\":2,\"name\":\"Gson Taro\",\"target\":\"20200230\"},");
        jsonReader.append(" {\"age\":3,\"name\":\"Gson Taro\",\"target\":\"20200212\"}");
        jsonReader.append("]");
```

## 結果はこちら
```
------------------------------------------->
Person1#toString: [Person1 [age=1, name=Gson Taro, noUse=null, target=Mon Feb 10 00:00:00 JST 2020], Person1 [age=2, name=Gson Taro, noUse=null, target=Sun Mar 01 00:00:00 JST 2020], Person1 [age=3, name=Gson Taro, noUse=null, target=Wed Feb 12 00:00:00 JST 2020]]
------------------------------------------->
```

ここで、面白いことに2020/2/30が2020/3/1に変換されています。
### この部分Gsonのソースを読んでみます。
Dateに変換しているのは[この部分](https://github.com/google/gson/blob/55acc23d8656a9fe5b19b92029a2dc7277e3765c/gson/src/main/java/com/google/gson/internal/bind/DateTypeAdapter.java#L78)っぽいですね。
ここはなんとかカスタマイズできそう。。。

ということで調べてみると、[この部分](https://github.com/google/gson/blob/55acc23d8656a9fe5b19b92029a2dc7277e3765c/gson/src/main/java/com/google/gson/GsonBuilder.java#L431)で日付のフォーマットを指定できそう。
使ってみます。

```test.java
        jsonReader.append("[");
        jsonReader.append(" {\"age\":1,\"name\":\"Gson Taro\",\"target\":\"2020-02-10\"},");
        jsonReader.append(" {\"age\":2,\"name\":\"Gson Taro\",\"target\":\"20200230\"},");
        jsonReader.append(" {\"age\":3,\"name\":\"Gson Taro\",\"target\":\"2020/02/12\"}");
        jsonReader.append("]");
        Gson gsonReader = new GsonBuilder().setDateFormat("yyyy/MM/dd").create();
        Type listType = new TypeToken<List<Person1>>(){}.getType();
        List<Person1> p1 = gsonReader.fromJson(jsonReader.toString(), listType);

        System.out.println("------------------------------------------->");
        System.out.println("Person1#toString: " + p1);
        System.out.println("------------------------------------------->");
```

結果はパース成功です！

```
------------------------------------------->
Person1#toString: [Person1 [age=1, name=Gson Taro, noUse=null, target=Mon Feb 10 00:00:00 JST 2020], Person1 [age=2, name=Gson Taro, noUse=null, target=Sun Mar 01 00:00:00 JST 2020], Person1 [age=3, name=Gson Taro, noUse=null, target=Wed Feb 12 00:00:00 JST 2020]]
------------------------------------------->
```

いいですね。非常に使いやすい！！