動作確認環境
- Java 16
- Jackson 2.12.5
JsonNodeを取得する
path, get, at
keyが存在する場合
JsonNodeを取得するにはpath, get, atの3つの方法がある。
pathとgetは今いるJSONのノード内のkeyを指定する。atは今いるJSONのノード内をルートとして/を使ったパスでkeyを指定する(常に/から開始する必要があり、/から開始しないとIllegalArgumentExceptionが発生する)。
java.lang.IllegalArgumentException: Invalid input: JSON Pointer expression must start with '/'`
具体的なコードを書くと以下のようになる。
// import static java.lang.System.out;
static ObjectMapper objectMapper = new ObjectMapper();
public static void main(String[] args) throws JsonProcessingException {
String json = "{\"key\":\"value\"}";
JsonNode node = objectMapper.readTree(json);
JsonNode keyNodeByPath = node.path("key");
JsonNode keyNodeByGet = node.get("key");
JsonNode keyNodeByAt = node.at("/key");
out.println(keyNodeByPath.equals(keyNodeByGet) && keyNodeByPath.equals(keyNodeByAt)); // true
}
keyが存在しない場合
先程のコードでは、path, get, atに実際に存在するkeyを指定した。存在しないkeyの場合はどうなるか。
public static void main(String[] args) throws JsonProcessingException {
String json = "{\"key\":\"value\"}";
JsonNode node = objectMapper.readTree(json);
out.println(node.path("notExist").getClass()); // MissingNode
out.println(node.get("notExist")); // null
out.println(node.at("/notExist").getClass()); // MissingNode
}
pathとatはMissingNodeが返り、getはnullが返る。
getはNullPointerExceptionが発生しやすく使いづらいかもしれない。
JSONのvalueを取得する
textValue, asText
keyが存在し、valueの型が想定通りの場合
path等で目的のvalueがあるJsonNodeを取得した後は、そのJsonNodeのvalueを取得するために、valueが文字列であればtextValueかasTextを実行する。
public static void main(String[] args) throws JsonProcessingException {
String json = "{\"key\":\"value\"}";
JsonNode node = objectMapper.readTree(json);
out.println(node.path("key").textValue()); // value
out.println(node.path("key").asText()); // value
}
keyが存在し、valueの型が想定通りでない場合
valueは今実際に文字列だが、想定では数字が返ってくるはずだとする。数字が返るはずなので、textValueではなくintValue、asTextではなくasIntで実行する。
out.println(node.path("key").intValue()); // 0
out.println(node.path("key").asInt()); // 0
実際には数字に変換できない文字列が返ってきたので、0になってしまった。
他にも文字列だと想定していたのに、実際にはオブジェクトだとnullや空文字が返ってしまう。
out.println(node.textValue()); // null
out.println(node.asText()); // emtpy string
数値系(Int, Long, Double)と真偽(Boolean)はプリミティブ型がメソッドの返り値になり、valueの型が想定通りではない場合にはデフォルト値になるので、~Valueもas~も同じ結果になる。
文字列だけはnullが返るか空文字が返るかの違いがある。(メソッドの返り値がStringでプリミティブ型じゃないのが原因だから???)
もし文字列の場合にasTextでもnullを返したければasText(String defaultValue)を使うといい。
out.println(node.path("notExist").textValue()); // null
out.println(node.path("notExist").asText(null)); // null
as~にはデフォルト値を指定できるメソッドがオーバーロードされている。
keyが存在しない場合
keyが存在しない場合は、path等で取得したJsonNodeがMissingNodeになる。これに対してtextValue等を実行した結果は、「keyが存在し、valueの型が想定通りでない場合」と同じになる。
keyが存在するが、valueがnullの場合
valueがnullの場合、asTextでは文字列として"null"が返ってきてしまうため注意が必要。
public static void main(String[] args) throws JsonProcessingException {
String json = "{\"key\":null}";
JsonNode node = objectMapper.readTree(json);
out.println(node.path("key").textValue()); // null
// textValueで取得するとnullになる
out.println(node.path("key").textValue() == null); // true
out.println(node.path("key").asText()); // null
// asTextで取得すると "null" になる
out.println(Objects.equals(node.path("key").asText(), "null")); // true
}
intValue, asIntではとも0になる。これについては先ほど見た通り「プリミティブ型がメソッドの返り値になり、valueの型が想定通りではない場合にはデフォルト値になるので、~Valueもas~も同じ結果」である。
as~は種類が少ないのに対して~Valueは種類が多い
他の違いとしてはas~は種類が少ないのに対して~Valueは種類が多い。
