Tidak dapat menghapus JSON sebagai tipe abstrak
Saat menjalankan tes yang deserialisasi string JSON, saya mendapatkan pesan kesalahan:
Tidak dapat membatalkan panggilan JSON sebagai jenis abstrak: TestController.Item
JSON berisi daftar objek yang abstrak dan tidak mungkin dilakukan deserialisasi.
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);
}
}
}
Ini adalah kelas tesnya:
@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) {
}
}
}
Saya menemukan permintaan tarik github dengan kesalahan yang sama. Ada Pembaruan Kritis dan saya yakin ini menyebabkan masalah.
Apakah Anda tahu cara mengatasi masalah itu?
Jawaban
Bahkan ketika kode ini akan dikompilasi dan dijalankan, ia memiliki masalah; Anda tidak bisa benar-benar membuat instance SomeItem di dalam daftar Item, karena pengurai JSON tidak akan tahu subjenis apa yang sebenarnya Anda gunakan.
Karena itu, Pembaruan Kritis sebenarnya adalah hal yang baik, karena memperbaiki perilaku menyimpang dengan jenis kode ini. Solusinya adalah membuat objek dalam memori secara manual.
Ini juga menunjukkan kemungkinan cacat desain, jika ini dimaksudkan untuk digunakan dengan semacam API yang akan menggunakan JSON. Itu tidak akan berfungsi, karena sistem tidak dapat menentukan jenis subkelas yang benar untuk digunakan untuk tipe data, dan dalam bahasa yang diketik dengan kuat seperti Apex, itu bermasalah.
Karena semuanya ditandai TestVisible, solusi yang tepat adalah membuat objek secara manual:
TestController.SomeClass wrapper = new TestController.SomeClass();
wrapper.items = new TestController.SomeItem[0];
wrapper.items.add(new TestController.SomeItem());
// etc //
Singkatnya, tidak ada solusi langsung. Anda harus mampu mendesentralisasi ke kelas konkret. Jika Anda tidak bisa, maka pilihan Anda adalah sesuatu seperti membangun secara manual (di atas), menggunakan JSONGenerator, atau menggunakan Objek generik (misalnya List<Map<String, Object>>
).
Saya mengalami masalah ini hari ini karena pembaruan kritis yang diaktifkan. Saya bisa menyelesaikannya dengan mengubah kelas abstrak saya menjadi kelas virtual.