yonet77的な雑記帳

日々思いついたネタなどを書き留めておきます

Force.comでのJSON Support

突然ですが、お仕事ではForce.com上での開発が多いです。(というか、大半)
そんな中で気になったことなど、ココに書き残します。

JSON Support的なお話

Winter '12 からJSONがネイティブでサポートされるようになって、JSONObjectを使っていた頃が懐かしく感じられます。(苦笑)
そんなJSON SupportのdeserializeでJOJO程ではないですが奇妙な挙動に遭遇しました。

基本

元々のリファレンスには、

Deserializes the specified JSON string into an Apex object of the specified type.
The jsonString argument is the JSON content to deserialize.
The apexType argument is the Apex type of the object that this method creates after deserializing the JSON content.
The following example deserializes a Decimal value.

JSON Methodリファレンス

と説明書きがあって、付随するコードは

Decimal n = (Decimal)JSON.deserialize('100.1', Decimal.class);
System.assertEquals(n, 100.1);

という感じに紹介されています。
要は、JSON形式の文字列をApexオブジェクトに変換してくれます。

deserializeメソッドの第一引数にJSON文字列を、第二引数に「System.Type」を指定してます。
上記の例では、Decimal.class ですが、ココには標準オブジェクトやカスタムオブジェクトも指定できるみたいです。
例えば、

Account acc = (Account)JSON.deserialize('{"Name":"AAAA", "AccountNumber":"001", "AnnualRevenue":500000}', Account.class);
System.assertEquals(acc.Name, 'AAAA');

となります。

遭遇した奇妙な出来事

JOJOの冒険にはほど遠いですが、奇妙な挙動に遭遇しました。
ポルナレフ風に言えば、

あ…ありのまま 今起こった事を話すぜ!
『おれは日付もパースできたと思ったらいつのまにかエラーが起きてた』
な…何を言っているのかわからねーと思うがおれも何をされたのかわからなかった…

という感じですが、何を言ってるのか全く分からないので、実際のコードを交えてみます。

以下のコードをSandbox環境で実行してみました。
なお、「kanseibi__c」は日付のカスタム項目です。

String jsonString = '[{"Name":"TestName01", "AccountNumber":"001", "AnnualRevenue":500000, "kanseibi__c":"2011-12-30"}]';
List<Account> rtn = (List<Account>)JSON.deserialize(jsonString, List<Account>.class);
System.debug('*** rtn = ' + rtn);

結果:

USER_DEBUG [3]|DEBUG|*** rtn = (Account:{Name=TestName01, AnnualRevenue=500000.0, kanseibi__c=2011-12-30 00:00:00})

うん、思った通りの結果が返ってきました。パニックになる要素は微塵もありません。

では、今度はこんなコードを実行してみます。
なお、「gii__SalesOrder__c」というのは、とある管理パッケージのカスタムオブジェクトで、「gii__RequiredDate__c」は日付項目です。

String jsonString = '{"gii__RequiredDate__c":"2011-12-30", "gii__Released__c":true}';
gii__SalesOrder__c rtn = (gii__SalesOrder__c)JSON.deserialize(jsonString, gii__SalesOrder__c.class);
System.debug('** rtn =  ' + rtn);

結果:

FATAL_ERROR System.JSONException: Cannot deserialize instance of date from VALUE_STRING value 2011-12-30

日付項目に対して、同じ日付を指定したのに・・・JSON Exceptionが返ってた・・・だとッ!?
 「意外!それはJSONExceptionッ!」
と言わんばかりに意外な結果でした。。
※ちなみに、管理パッケージ下にないカスタムオブジェクトの日付項目はちゃんと読み込んでくれました。


Sandbox環境が悪いのか、管理パッケージが悪いのか・・どういう条件下でエラーが発生するのか特定できてないですが、同じ日付文字列を指定しただけなのに挙動が変わるってのは・・なかなか興味深いところです。(って自分だけかも。。)

もう少し色々調べてみようと思いますが
 「そんなの当たり前だゼー!こうすればいいんだよッ!!」
というのがありましたら、ぜひツッコミ下さい。
※例えば、Salesforce ISV部隊に所属(している|していた歴代の)ナイスガイが
 「やれやれだぜ...」
と言いながらも華麗にツッコミしてくれることを期待しますww えぇ、あくまで例えです。


こんなん使ってどうすんの?的な話は次回にできたらいーなー・・と思います。


あ、ちなみに、このエントリーはForce.com Advent Calendarに参加しています。
ちょっと良く分からないのですが、2周しそうな雰囲気がでてるのがなんともはや。

「お…恐ろしいッ おれは恐ろしい!
なにが恐ろしいかって ジョースター! Force.com Advent Calendar が1周で終わらないんだ
2回担当するように変わっているんだぜーーーーッ!!」

と、シュトロハイムばりに恐怖を感じつつ。
(内容薄いなー... ごめんなさい。 次回はまだ未定です。)