2011/10/21 12:09:25

Winter’12のJSONサポートを使いこなす(2)

このエントリーをはてなブックマークに追加

前回、 ApexのデータをJSON文字列に変換する JSON.serialize() の変換結果を見てみました。
今回は JSON文字列を Apexのデータに変換する JSON.deserialize() の使い方をレポートします。
serialize()メソッドが比較的使いやすいメソッドだったのに対し、deserialize()メソッドは、使い方に注意が必要で、変換できないJSON文字列もあります。

JSON.deserailzie のインターフェースは、

 任意の型 JSON.deserialize(String jsonString, System.Type apexType); 
となっています。 引数として apexTypeを渡さなければいけない点に注意が必要です。

具体的な例として、 JSON文字列 ‘[1,2,3]‘‘["a","b","c"]‘ , ‘[[1,2],[3,4]]’ を変換する場合

 List<Integer> a = (List<Integer>)JSON.deserialize('[1,2,3]', List<Integer>.class);
List<String> b = (List<Integer>)JSON.deserialize('["a","b","c"]', List<String>.class);
List<List<Integer>> c =
	(List<List<Integer>>)JSON.deserialize('[[1,2],[3,4]]',List<List<Integer>>.class);

のように指定します。

では、 ‘[1,"b",3]‘‘[1, 2, ["a","b"]]’ はどうやって変換すればよいでしょうか。
いろいろ試してみると、以下のようになりました。

 List<Object> a = (List<Object>)JSON.deserialize('[1,"b",3]', List<Object>.class);
// ERROR: System.JSONException: Apex Type unsupported in JSON:

Object List<String> b = (List<String>)JSON.deserialize('[1,"b",3]', List<String>.class);
// OK: ただし["1","b","3"] に変換される

List<String> c = (List<String>)JSON.deserialize('[1,2,["a","b"]]', List<String>.class);
// ERROR: System.JSONException: Premature end of Apex List/Set

型が混在している場合List<Object>が使えればよいのですがエラーになります。
1つ目の例は、数値が文字列に変換されてもよければList<String>で受け取れますが、2番目の例はList<String>でもエラーになります。 このように、要素の型が均一でないと、変換ができない場合があります。

ここまで、JSONの配列の変換を見てきましたが、JSONのオブジェクトを読み込む場合は、どのような型を指定すればよいでしょうか。
まず、値の型がすべて同じJSONオブジェクトは、Mapに変換できます。
例えば ‘{“a”:1, “b”:2}’

 Map<String,Integer> a =
	(Map<String,Integer>)JSON.deserialize('{"a":1, "b":2}', Map<String,Integer>.class); 

のようなコードでMapに変換できます。
また、型が統一されていない場合でも、プロパティー名毎の型が決まっているなら、Apexクラスを定義することで変換できます。
例えば ‘{“a”:1, “b”:”xyz”, “c”:[2,3]}’ を変換する場合、 あらかじめクラスfooを用意して

class foo {
	Integer a;
	String b;
	List<Integer> c;
}
.... 略.... 
foo a = (foo)JSON.deserialize( '{"a":1, "b":"xyz", "c":[2,3]}' , foo.class);

のようなコードで変換可能です。
しかし、配列の時と同じで、型が混在している場合、例えばプロパティ”a”があるときは配列、ある時は文字列である次のようなJSON文字列は対応できません。

class foo {
	Integer a;
	String b;
	List c;
}
.... 略....
List<<foo> a = (List<<foo>)JSON.deserialize( '[{"a":1, "b":"xyz", "c":[2,3]},{"a":[1], "b":"xyz", "c":[2,3]}]' , List<<foo>.class);
// ERR: System.JSONException: Premature end of Apex List/Set

JSON.deserialize() の変換で注意することをまとめると

  1. あらかじめJSONの中身の型がわかっていないと変換できない
  2. 文字列と数値が混在している場合はStringを指定して受け取る
  3. 文字列と配列、あるいは数値とオブジェクトが混在している場合は変換できない場合がある

このような仕様を見ると JSON.serialize() と JSON.deserailize() メソッドは、Apexの型がまずあって、これをJavascriptとやり取りするときに使うための変換/逆変換メソッドとして設計されているようです。
逆に言えば、任意のJSONをApex側で処理する目的で用意したのではないというわけです。

とはいっても、マッシュアップとかで、任意のJSONを受け取りたい場合もあります。このような場合はどうすればよいでしょうか。
次回は、 System.JSONParser を使って、任意のJSONをApexのデータに変換するコード例を紹介したいと思います。

(有本)

admin
Page topへ