JSONを抽象型として逆シリアル化できません
JSON文字列を逆シリアル化するテストを実行すると、次のエラーメッセージが表示されます。
JSONを抽象型として逆シリアル化できません:TestController.Item
JSONには抽象オブジェクトのリストが含まれており、逆シリアル化することはできません。
public class TestController {
@Testvisible
private abstract class Item{
public String bla;
public String bla2;
}
public class SomeItem extends Item{
private SomeItem() {
bla = 'bla';
}
}
public class SomeClass{
@Testvisible private List<Item> items;
public Graph(List<SomeItem> someItems) {
items = new List<Item>();
items.addAll((List<Item>) someItems);
}
}
}
これはテストクラスです:
@IsTest
public class TestController_Test {
@IsTest
private static void testSomething() {
TestController.SomeClass someClass = (TestController.SomeClass) System.JSON.deserialize(json, TestController.SomeClass.class);
for(TestController.Item item : someClass.items) {
}
}
}
同じエラーのあるgithubプルリクエストが見つかりました。重大な更新があり、これが問題の原因であると確信しています。
その問題を解決する方法を知っていますか?
回答
このコードをコンパイルして実行する場合でも、問題がありました。JSONパーサーは実際に使用するサブタイプを認識しないため、Itemのリスト内でSomeItemを実際にインスタンス化することはできませんでした。
そのため、このタイプのコードでの異常な動作を修正するため、クリティカルアップデートは実際には良いことです。解決策は、メモリ内にオブジェクトを手動で作成することです。
これは、JSONを使用するある種のAPIで使用することを意図している場合、設計上の欠陥の可能性も示しています。システムがデータ型に使用するサブクラスの正しい型を決定できないため、それは単に機能しません。Apexのような強く型付けされた言語では、問題があります。
すべてがTestVisibleとマークされているため、正しい解決策はオブジェクトを手動で作成することです。
TestController.SomeClass wrapper = new TestController.SomeClass();
wrapper.items = new TestController.SomeItem[0];
wrapper.items.add(new TestController.SomeItem());
// etc //
要約すると、直接的な回避策はありません。具体的なクラスに逆シリアル化できる必要があります。できない場合、オプションは、手動で作成する(上記)、JSONGeneratorを使用する、または汎用オブジェクトを使用する(例List<Map<String, Object>>
)などです。
重要な更新がアクティブ化されたため、今日この問題が発生しました。抽象クラスを仮想クラスに変更することで解決できました。