動作確認環境
- 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
は種類が多い。