ProcessingでJSONをスマートに扱う

# 追記（2024/07/07）

ライブラリにしました。
https://github.com/enkatsu/JacksonP5

# はじめに

この記事は[Processing Advent Calendar 2017](https://qiita.com/advent-calendar/2017/processing) 23日目の記事です。
埋まっていなくて流れてしまっていたので、書かせていただきます。

今回はProcessingでJSONを扱う方法の一つを書いていきます。
Processingには標準で[JSONObject](https://processing.org/reference/JSONObject.html)や[JSONArray](https://processing.org/reference/JSONArray.html)というJSONを扱うクラスがあります。

公式リファレンスのサンプルではこんな風に使っています。

```java
JSONObject json;

void setup() {

  json = loadJSONObject("data.json");

  int id = json.getInt("id");
  String species = json.getString("species");
  String name = json.getString("name");

  println(id + ", " + species + ", " + name);
}
```

WebAPIを叩く時も`loadJSONObject("http://webapi.com/users")`のように使用してJSONObjectを生成するのが普通ですが、いちいち`json.getString("name")`とかでパースしてUserクラスなどに入れていくのも面倒です。
なので今回は[Jackson](https://github.com/FasterXML/jackson)というJSONを扱う為のライブラリを使います。

# 導入

まずはjarファイルをProcessingライブラリのフォーマットに整えます。
ダウンロードしてくるjarファイルはこれらです。

- [jackson-core-2.9.3.jar](http://central.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.9.3/jackson-core-2.9.3.jar)
- [jackson-databind-2.9.3.jar](http://central.maven.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.9.3/jackson-databind-2.9.3.jar)
- [jackson-annotations-2.9.3.jar](http://central.maven.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.9.3/jackson-annotations-2.9.3.jar)

これらをダウンロードしたら`PROCESSING_PATH/libraries`以下に適当な名前のディレクトリを作ります。
自分は`jacksonP5`としました。[Jackson 5](https://ja.wikipedia.org/wiki/%E3%82%B8%E3%83%A3%E3%82%AF%E3%82%BD%E3%83%B35)みたいですね。
ディレクトリを作ったらその中に`library`ディレクトリを作って、先ほどのjarファイルを入れます。
こんな構造になります。

```
.
└── library
    ├── jackson-annotations-2.9.3.jar
    ├── jackson-core-2.9.3.jar
    └── jackson-databind-2.9.3.jar
```

これでライブラリの導入は完了です。
ここでProcessingを再起動しておきましょう。

# サンプル

では早速`JSON -> Javaオブジェクト`のサンプルを書いていきます。
ここでの注意点はインスタンス化したいクラスは外部のJavaファイルで用意することです。
pdeファイル内に書くと`JsonMappingException`が発生します。
おそらく`PApplet`を継承したメインクラスの内部クラスとして扱われるのが原因ではないかと思います。
Processing IDEからJavaファイルを作る方法は、New Tab(command + shift + N)で入力するファイル名の末尾に`.java`と入力すれば生成されます。今回は`User.java`と入力します。

```java:JacksonSample.pde
import com.fasterxml.jackson.databind.ObjectMapper;

String json = "{\"id\": 1, \"name\": \"太郎\", \"age\": 25, \"job\": \"エンジニア\"}";

void setup() {
  println(json);
  ObjectMapper mapper = new ObjectMapper();
  try {
    User user = mapper.readValue(json, User.class);
    System.out.println(user);
  }
  catch (IOException e) {
    println(e);
  }
}

void draw() {
}
```

```java:User.java
import com.fasterxml.jackson.annotation.JsonProperty;

public class User {
  @JsonProperty("id")
  private int id;
  @JsonProperty("name")
  private String name;
  @JsonProperty("age")
  private int age;
  @JsonProperty("job")
  private String job;
  
  public String toString() {
    return String.format("ID %d番の%s %d歳です。職業は%sです。", id, name, age, job);
  }
}
```

実行したらこんな感じに出力されると思います。

```
{"id": 1, "name": "太郎", "age": 25, "job": "エンジニア"}
ID 1番の太郎 25歳です。職業はエンジニアです。
```

これでWeb APIリファレンスがあれば、いちいちパースするコードを書かなくて済みますね。

# WebAPIを叩く

試しに[json-server](https://github.com/typicode/json-server)を使ってWebAPIを叩いてみます。
json-serverの使い方は以前に[こちら](https://qiita.com/enkatsu/items/354a347ac9644acc2da7)の記事に書いたので見てみてください。
メインのソースコードをこんな風にすると、json-serverのID　0のユーザが取得できます。

```java:JacksonSample.pde
import com.fasterxml.jackson.databind.ObjectMapper;
import http.requests.*;

String URL = "http://localhost:3000/users/1";

void setup() {
  GetRequest get = new GetRequest(URL);
  get.send();
  ObjectMapper mapper = new ObjectMapper();
  try {
    User user = mapper.readValue(get.getContent(), User.class);
    System.out.println(user);
  }
  catch (IOException e) {
    println(e);
  }
}

void draw() {
}
```

出力

```
ID 1番の二郎 30歳です。職業は魔法使いです。
```

# 配列を受け取る

`http://localhost:3000/users`にリクエストして配列を受け取りたいときは`TypeReference`を使うみたいです。

```java:JacksonSample.pde
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.type.TypeReference;
import http.requests.*;

String URL = "http://localhost:3000/users";

void setup() {
  GetRequest get = new GetRequest(URL);
  get.send();
  ObjectMapper mapper = new ObjectMapper();
  try {
    TypeReference typeRef = new TypeReference<ArrayList<User>>(){};
    ArrayList<User> users = mapper.readValue(get.getContent(), typeRef);
    for (User user : users) {
      System.out.println(user);
    }
  }
  catch (IOException e) {
    println(e);
  }
}

void draw() {
}
```

出力

```
ID 0番の太郎 30歳です。職業は勇者です。
ID 1番の二郎 30歳です。職業は魔法使いです。
```

ではでは