ApexのJSON.deserializeとJSON.deserializeStrictの違い

2022.07.07

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ApexでJSONを処理するコードを書いていて、JSON.deserializeとJSON.deserializeStrictの違いが気になったので確認してみました。

前提

リファレンスには以下のように記載されています。

JSON.deserialize

JSON コンテンツに、System.Type 引数に存在しない属性 (存在しない項目やオブジェクトなど) が含まれている場合、一定の状況で並列化に失敗します。Salesforce API バージョン 34.0 以前を使用して JSON コンテンツをカスタムオブジェクトまたは sObject に並列化すると、無関係な属性が渡されたときにこのメソッドが実行時例外を発生させます。JSON コンテンツを API の全バージョンの Apex クラスまたは API バージョン 35.0 以降のオブジェクトに並列化したときは、例外が発生しません。例外が発生しない場合、このメソッドは無関係な属性を無視して、残りの JSON コンテンツを解析します。

JSON.deserializeStrict

JSON 文字列内のすべての属性は、指定された型に存在する必要があります。JSON コンテンツに、System.Type 引数に存在しない属性 (存在しない項目やオブジェクトなど) が含まれている場合、一定の状況で並列化に失敗します。無関係な属性のある JSON コンテンツを Apex クラスに並列化すると、API のどのバージョンでもこのメソッドが例外を発生させます。ただし、このメソッドを使用して JSON コンテンツをカスタムオブジェクトまたは sObject に並列化する場合は、例外が発生しません。

System.Typeに存在しない属性が含まれているJSONを変換する場合、JSON.deserializeでは例外が発生せず残りのJSONを解析するが、JSON.deserializeStrictでは例外が発生する、という事のようです。(バージョン 34.0以前のAPIを除く)

確認

System.Typeの引数用にnameとageという2つ属性を持つCatオブジェクトを定義します。

public class Cat {
    public String name;
    public Integer age;
}

Catオブジェクトにあるnameとageに加え、catBreedの要素を持つJSONを作成して変換してみます。

JSON.deserialize

String jsonStr = '{"name":"ねこ", "age":1, "catBreed":"American Shorthair"}';
Cat neko = (Cat)JSON.deserialize(JsonStr, Cat.class);        
System.debug(neko);
Cat:[age=1, name=ねこ]

JSON.deserializeStrict

String jsonStr = '{"name":"ねこ", "age":1, "catBreed":"American Shorthair"}';
Cat neko = (Cat)JSON.deserializeStrict(JsonStr, Cat.class);        
System.debug(neko);
System.JSONException: Unknown field: JsonParseTest.Cat.catBreed

JSON.deserializeでは追加したcatBreedの要素に関係なく、nameとageの要素が変換されました。
しかし、JSON.deserializeStrictでは追加したcatBreedの要素がUnknown fieldとなり例外が発生します。


次にnameだけを持つJSONを作成して変換してみます。

JSON.deserialize

String jsonStr = '{"name":"ねこ"}';
Cat neko = (Cat)JSON.deserialize(JsonStr, Cat.class);        
System.debug(neko);
Cat:[age=null, name=ねこ]

JSON.deserializeStrict

String jsonStr = '{"name":"ねこ"}';
Cat neko = (Cat)JSON.deserializeStrict(JsonStr, Cat.class);        
System.debug(neko);
Cat:[age=null, name=ねこ]

JSON.deserialize、JSON.deserializeStrict共にnameの値のみが変換され、ageはnullとなりました。
要素が足りない場合はJSON.deserializeStrictでも例外は発生しません。

まとめ

Strict(厳密)の意味通り、JSON.deserializeStrictでは変換するオブジェクトに無い要素が含まれていないかを厳しくチェックするようです。JSONのバリデーションをする際はJSON.deserializeStrictで余計な要素が含まれていないかを判定し、変換後の値がnullかどうかで必要な要素が含まれているかを判定するのが良さそうです。