【Java】ライブラリを用いてJson文字列の要素を編集してみる


# やりたいこと
```java
String jsonString = "{\"Apple\":{" 
						+ "\"cost\":\"0\"},"
					+ "\"Pen\":{"
						+ "\"cost\":\"0\"}}";
```
やりたいのは以下の2点です。

* 上記のJson文字列の`"0"`にあたる部分を編集したい。
* 新たなキー`"ApplePen"`を追加したい。

今回は以下の代表的(？)なJsonを操作するためのライブラリを使ってみます。

* Gson  
* Jackson

# 実行環境
Android Studio: 3.4.1
gradle: 5.1.1

# ライブラリ追加
追加するライブラリをbuild.gradleのdependenciesブロックに記述します。

	dependencies {
		...
	    implementation 'com.google.code.gson:gson:2.8.5'
	    implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
	    implementation 'org.glassfish:javax.json:1.1.4'
	}


# Gson
作成したメソッド(editJson)でJson文字列を
`Map<String, MAP<String, String>>`という形に置き換え(Gson.fromJson)、目的のキーと値を代入しています。
代入後、Mapを再びJson文字列に変換しています(Gson.toJson)。

本題と逸れますが、
[Json => 他のクラス] の変換を「Deserialization」、
[他のクラス => Json] の変換を「Serialization」と呼ぶんですね。

```java
import com.google.gson.Gson;
...

public class GsonExample {

	String jsonString = "{\"Apple\":{" +
							"\"cost\":\"0\"}," +
						"\"Pen\":{" + 
							"\"cost\":\"0\"}}";
	
	public void main() {
		editJson("Apple", "100");
		/*
			{
				"Apple": {
					"cost": "100"
				},
				"Pen": {"
					"cost": "0"
				}
			}"
		*/
		editJson("ApplePen", "");
		/*
			{
				"Apple": {
					"cost": "100"
				},
				"Pen": {"
					"cost": "0"
				}
				"ApplePen": {"
					"cost": "0"
				}
			}"
		*/
	}

	private void editJson(String key, String str) {
		if (str.isEmpty()) str = "0";
        Map<String, String> innerMap = new HashMap<>();
        innerMap.put("cost", str);

    	Gson gson = new Gson();
    	// Json文字列をMapに変換
        Map<String, Map<String,String>> jsonMap = gson.fromJson(jsonString, Map.class);
        jsonMap.put(key, innerMap);
    	// Mapを再びJson文字列に変換
        jsonString = gson.toJson(jsonMap);
    }
}
```

# Jackson
Gsonの時とほぼ同様に置き換え処理を行なっています。
Jacksonでは`ObjectMapper`のメソッドを介してJsonを変換します。

```java
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
...

public class JacksonExample {
	// main()は省略 

    private void editJson(String str, String key) {
		if (str.isEmpty()) str = "0";
        Map<String, Object> map = null;
        Map<String, String> innerMap = new HashMap<>();
        innerMap.put("cost", str);

        ObjectMapper mapper = new ObjectMapper();
        try {
        	// Json文字列をMapに変換
            map = mapper.readValue(json, 
									new TypeReference<Map<String, Object>>() {});
        } catch (IOException e) {
            e.printStackTrace();
        }
        map.put(key, innerMap);
        try {
        	// Mapを再びJson文字列に変換
            json = mapper.writeValueAsString(map);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
	}
}
```

# javax.jsonについて
javax.jsonライブラリでも同様の実装ができるか試してみましたが、行き詰まってしまいました。

* Json文字列をMapに変換できなそう？
* JsonObjectに対して書き換え処理ができない。(UnsupportedOperationException発生)

# 感想
* Gsonは使いやすい。
* TypeReferenceがなにもわからない。

# 20.09.27追記 （org.json.JSONObjectについて）
JsonをMapに変換して値を追加するだけなら`org.json.JSONObject`でもいけることに気づきました。

```java
import org.json.JSONException;
import org.json.JSONObject;
...

public class JSONExample {
	// main()は省略 

    private void editJson(String str, String key) {
		if (str.isEmpty()) str = "0";
        Map<String, String> innerMap = new HashMap<>();
        innerMap.put("cost", str);
        try {
            JSONObject jsonObject = new JSONObject(json);
            jsonObject.put(key, new JSONObject(innerMap));
            json = jsonObject.toString();
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
}
```

# 参考文献
以下の記事を参考にさせていただきました。

* Gson, Jacksonの使用方法について
	* https://qiita.com/riversun/items/cdd990e96c2bbf9cb043 
* Gson
	* https://sites.google.com/site/gson/gson-user-guide  
	* https://www.codeflow.site/ja/article/gson-json-to-map
* Jackson
	* https://salumarine.com/how-to-convert-json-string-to-map-in-java/
* javax.json
	* https://spring.pleiades.io/specifications/platform/8/apidocs/javax/json/JsonObject.html