ベビーサンになりたい

勉強したことと思ったこととか

jsonデータの取得方法〜asXxxxとxxxxValueのちがい

jsonの値を取得する処理を調べながら書いてたら、asTextとtextValueが混在してて違いが気になったのでメモ。
リファレンスを読みながら、文字列・数値・ブール値を取得&出力するコードで結果を確認していく。

jacksonのバージョンは2.9。
リファレンスはこれ↓
JsonNode (jackson-databind 2.9.0 API)

以下の実験用jsonデータを読み取る

// sample.json
{
    "string": {
        "name": "apple",
        "price": "200",
        "isStock": "true"
    },
    "int": {
        "name": 100,
        "price": 300,
        "isStock": 0
    },
    "boolean": {
        "name": true,
        "price": true,
        "isStock": false
    },
    "null": {
        "name": null,
        "price": null,
        "isStock": null
    }
}

asText()

Method that will return a valid String representation of the container value, if the node is a value node (method isValueNode() returns true), otherwise empty String.

これは「値を参照する場合、コンテナ値の有効な文字列表現を返して、それ以外(=キー)を取得する時は空文字を返す」らしい。
コンテナ値ってなんだろって思ったけど、バシッとくる答え見つからなかった。
javaUtilクラスにある型っていうのかな。よくいう"普通の型"なら文字列に読み替えてくれるぽいな。
nullの時でもぬるぽにならないから、気づかずに画面にnullって表示されて初めて気づくのとか悔しいから気をつけないと。

// asText
String string_name_asText = root.get("string").get("name").asText();  //"apple"
System.out.println(string_name_asText); //apple

String int_name_asText = root.get("int").get("name").asText();    //100
System.out.println(int_name_asText);    //100

String boolean_name_asText = root.get("boolean").get("name").asText();    //true
System.out.println(boolean_name_asText);    //true

String null_name_asText = root.get("null").get("name").asText();  //null
System.out.println(null_name_asText);   //null

//キーを取得する時
String reading_key_asText = root.get("string").asText(); //"string": { "name": "apple", "price": "200", "isStock": "true" }
System.out.println(reading_key_asText); //"" (空文字)

textValue

Method to use for accessing String values. Does NOT do any conversions for non-String value nodes; for non-String values (ones for which isTextual() returns false) null will be returned. For String values, null is never returned (but empty Strings may be)

これは文字列以外が入ってたらnullが返される。
最後の文曰く、nullじゃなくて空文字が返されることもあるのか?これは謎だ。。。
これはキーを取得するとnullが返る。

//textValue
String string_name_textValue = root.get("string").get("name").textValue();    //"apple"
System.out.println(string_name_textValue);  //apple

String int_name_textValue = root.get("int").get("name").textValue();  //100
System.out.println(int_name_textValue); //null

String boolean_name_textValue = root.get("boolean").get("name").textValue();  //true
System.out.println(boolean_name_textValue); //null

String null_name_textValue = root.get("null").get("name").textValue();    //null
System.out.println(null_name_textValue);    //null

//キーを取得する時
String reading_key_textValue = root.get("string").textValue();   //"string": { "name": "apple", "price": "200", "isStock": "true" }
System.out.println(reading_key_textValue);  //null

asInt

Method that will try to convert value of this node to a Java int. Numbers are coerced using default Java rules; booleans convert to 0 (false) and 1 (true), and Strings are parsed using default Java language integer parsing rules. If representation cannot be converted to an int (including structured types like Objects and Arrays), default value of 0 will be returned; no exceptions are thrown.

文字列の値を取得する場合、数値に変換できたらその数を、変換できない時は0を返す。
どうやらブール値は0(false)と1(true)に変換されるらしい。

//asInt
int string_price_asInt = root.get("string").get("price").asInt();    //"200"
System.out.println(string_price_asInt); //200

int string_name_asInt = root.get("string").get("name").asInt();  //"apple"
System.out.println(string_name_asInt);  //0

int int_price_asInt = root.get("int").get("price").asInt();  //100
System.out.println(int_price_asInt);    //100

int boolean_price_asInt = root.get("boolean").get("price").asInt();  //true
System.out.println(boolean_price_asInt);    //1

int null_price_asInt = root.get("null").get("price").asInt();    //null
System.out.println(null_price_asInt);   //0

intValue

Returns integer value for this node, if and only if this node is numeric (isNumber() returns true). For other types returns 0. For floating-point numbers, value is truncated using default Java coercion, similar to how cast from double to int operates.

これは数値でない場合は0を返す。bool値も変換してくれない。
double型の時は、intにキャストする時と同じように切り捨てて返す。

//intValue
int string_price_intValue = root.get("string").get("price").intValue();  //"200"
System.out.println(string_price_intValue);  //0

int int_price_intValue = root.get("int").get("price").intValue();    //300
System.out.println(int_price_intValue); //300

int boolean_price_intValue = root.get("boolean").get("price").intValue();    //true
System.out.println(boolean_price_intValue); //0

int null_price_intValue = root.get("null").get("price").intValue();  //null
System.out.println(null_price_intValue);    //0

asBoolean

Method that will try to convert value of this node to a Java boolean. JSON booleans map naturally; integer numbers other than 0 map to true, and 0 maps to false and Strings 'true' and 'false' map to corresponding values. If representation cannot be converted to a boolean value (including structured types like Objects and Arrays), default value of false will be returned; no exceptions are thrown.

これもasStringやasIntと同じように、trueまたはfalseに変換できるなら型が違くても変換してくれる。
asBooleanでは、
文字列の場合、"true"or"false"なら自動変換でそれ以外の文字列はfalse、数値なら0はfalse、整数はtrueへ自動変換してくれる。

//asBoolean
boolean string_isStock_asBoolean = root.get("string").get("isStock").asBoolean();    //"true"
System.out.println(string_isStock_asBoolean);   //true

boolean int_isStock_asBoolean = root.get("int").get("isStock").asBoolean();  //0
System.out.println(int_isStock_asBoolean);  //false

boolean int_price_asBoolean = root.get("int").get("price").asBoolean();  //300
System.out.println(int_price_asBoolean);    //true

boolean boolean_isStock_asBoolean = root.get("boolean").get("isStock").asBoolean();  //false
System.out.println(boolean_isStock_asBoolean);  //false

boolean null_isStock_asBoolean = root.get("null").get("isStock").asBoolean();    //null
System.out.println(null_isStock_asBoolean); //false

booleanValue

Method to use for accessing JSON boolean values (value literals 'true' and 'false'). For other types, always returns false.

ここまできたら予想通りだが、boolean型以外の値はfalseを返す。

//booleanValue
boolean string_isStock_booleanValue = root.get("string").get("isStock").booleanValue();  //"true"
System.out.println(string_isStock_booleanValue);    //false

boolean int_isStock_booleanValue = root.get("int").get("isStock").booleanValue();    //0
System.out.println(int_isStock_booleanValue);   //false

boolean boolean_isStock_booleanValue = root.get("boolean").get("isStock").booleanValue();    //false
System.out.println(boolean_isStock_booleanValue);   //false

boolean null_isStock_booleanValue = root.get("null").get("isStock").booleanValue();  //null
System.out.println(null_isStock_booleanValue);  //false

おまけ asXxxx(defaultValue)

asXxxx()をオーバーロードするメソッドもある。 これは値がnullの時に、引数に指定したdefaultValueが返る。
これ使えばnullチェックしなくて済むから便利、、、
ちょっとだけ例

//asText(defalutValue)
String string_name_asText_defalut = root.get("string").get("name").asText("secret!");  //"apple"
System.out.println(string_name_asText_defalut); //apple

String null_name_asText_defalut = root.get("null").get("name").asText("secret!");  //null
System.out.println(null_name_asText_defalut);   //secret!

おわりに

シンプルだけどひとつずつ調べると、使い勝手が良くなるようによーく考えてAPI作ってくれてるんだな〜って思った。