JsonConverter<T> adalah titik penyisipan ketika perilaku default JsonSerializer tidak memadai. Konverter kustom memiliki dua method wajib: Write menentukan bagaimana nilai ditulis ke JSON, sedangkan Read menentukan bagaimana nilai dibaca dari JSON. Karena Read kita tulis sendiri, validasi khusus seperti menolak nilai negatif dapat dilakukan langsung di titik masuk data.

Kapan Menulis Konverter Sendiri #

  • Tipe diserialisasi ke bentuk khusus, misalnya Rupiah sebagai angka atau tanggal dengan pola tertentu.
  • Nilai perlu divalidasi ketika data masuk, sehingga payload tidak valid ditolak sejak tepi sistem.
  • Format pihak ketiga memakai penulisan nonstandar, misalnya durasi sebagai teks "1h 30m".

Contoh Konverter untuk Tipe Rupiah #

Tipe Rupiah membungkus angka int. Konverter berikut menulis nilai apa adanya sebagai angka dan menolak nilai negatif saat membaca:

csharp
public class KonverterRupiah : JsonConverter<Rupiah>
{
    public override Rupiah Read(ref Utf8JsonReader reader, Type typeToConvert,
        JsonSerializerOptions options)
    {
        int nilai = reader.GetInt32();
        if (nilai < 0)
        {
            throw new JsonException("Nilai rupiah tidak boleh negatif.");
        }
        return new Rupiah { Nilai = nilai };
    }

    public override void Write(Utf8JsonWriter writer, Rupiah value,
        JsonSerializerOptions options)
    {
        writer.WriteNumberValue(value.Nilai);
    }
}

Konverter ditempelkan ke properti dengan atribut [JsonConverter(typeof(KonverterRupiah))], lalu serialisasi berjalan:

csharp
var produk = new ProdukRupiah { Nama = "Kopi Gayo", Harga = new Rupiah { Nilai = 45000 } };

string json = JsonSerializer.Serialize(produk);
Console.WriteLine(json);

try
{
    JsonSerializer.Deserialize<ProdukRupiah>("""{"Nama":"Kopi Toraja","Harga":-5}""");
}
catch (JsonException e)
{
    Console.WriteLine($"JsonException: {e.Message}");
}

Output yang Dihasilkan:

text
{"Nama":"Kopi Gayo","Harga":45000}
JsonException: Nilai rupiah tidak boleh negatif.

Mari kita bedah bagian pentingnya:

  1. Read: reader berada tepat pada token angka; GetInt32 membacanya, dan kondisi nilai < 0 melempar JsonException dengan pesan kita sendiri.
  2. Write: writer.WriteNumberValue menulis Nilai sebagai angka JSON tanpa tanda kutip.
  3. Skenario kedua: JSON dengan "Harga":-5 gagal deserialisasi, dan blok catch menangkap pesan validasi tersebut sebelum data tidak valid menyebar ke lapisan bisnis.

Method Read menerima parameter ref Utf8JsonReader yang posisinya sudah tepat berada pada token nilai properti tersebut, sedangkan Write menerima Utf8JsonWriter yang siap menerima token baru. Konverter berjalan otomatis setiap kali serializer bertemu properti bertipe Rupiah, baik di akar payload maupun di dalam koleksi yang bersarang, sehingga aturan berlaku seragam di seluruh aplikasi.