Go 1.25 encoding/json v1 vs v2 Karşılaştırması
Go'nun encoding/json
paketinin v2 sürümü, mevcut v1 sürümünün çeşitli eksikliklerini (tutarsızlık, beklenmedik davranışlar, performans sorunları) gidermeyi amaçlayan yeni bir implementasyondur. Bu, goexperiment.jsonv2
build tag'i aracılığıyla etkinleştirilen deneysel bir özelliktir.
En önemli nokta şudur: v2 etkinleştirildiğinde, v1, v2 implementasyonu üzerinde v1'in davranışlarını taklit eden bir uyumluluk katmanı olarak işlev görür. Bu, v2_v1.go
dosyasındaki DefaultOptionsV1()
fonksiyonu aracılığıyla gerçekleştirilir. Yani, v2, v1'in davranışını tamamen yeniden üretebilen seçenekler sunarken, aynı zamanda daha katı ve öngörülebilir yeni varsayılan davranışlar önerir.
v2'nin başlıca hedefleri şunlardır:
- Doğruluk ve Öngörülebilirlik İyileştirmesi: Varsayılan olarak daha katı kurallar (örn. büyük/küçük harf duyarlılığı, yinelenen anahtarların yasaklanması) uygulayarak beklenmedik davranışları azaltır.
- Performans İyileştirmesi: Ayrıştırma ve kodlama motoru yeniden tasarlanarak verimlilik artırılmıştır.
- Esneklik ve Kontrol Alanının Genişletilmesi: Geliştiricilerin JSON işleme yöntemlerini ayrıntılı olarak kontrol etmelerini sağlayan kapsamlı bir Options sistemi sunar.
Başlıca Anlamsal/Davranışsal Farklılıklar
v2_test.go
dosyası temel alınarak v1 ve v2'nin davranış farklılıkları maddeler halinde düzenlenmiştir.
1. Alan Adı Eşleşmesi (Büyük/Küçük Harf Duyarlılığı)
- v1 Davranışı: JSON nesne üyelerini Go struct alanlarına Unmarshal ederken, büyük/küçük harf duyarsız bir eşleştirme yapar. Hem
"FirstName"
hem de"firstname"
,FirstName
alanına eşlenir. - v2 Davranışı: Varsayılan olarak büyük/küçük harf duyarlı bir eşleştirme yapar ve yalnızca tam olarak eşleşen alanları eşler.
- Değişiklik Nedeni: Büyük/küçük harf duyarsız eşleştirme, beklenmedik davranışlara neden olabilir ve eşleşmeyen alanları işlerken performans düşüşüne yol açabilir. v2, daha net ve öngörülebilir bir davranışı varsayılan olarak benimsemiştir.
- İlgili Seçenek: v2'de,
json:"...,case:ignore"
tag seçeneği kullanılarak alan bazında büyük/küçük harf duyarsızlığı açıkça etkinleştirilebilir veyajson.MatchCaseInsensitiveNames(true)
seçeneği global olarak uygulanabilir.
2. omitempty
Tag Seçeneğinin Anlam Değişikliği
- v1 Davranışı: Go değerinin "boş (empty) durumu"na göre alanı atlar. Burada "boş durum",
false
,0
,nil
pointer/interface, ve uzunluğu 0 olan array/slice/map/string anlamına gelir. - v2 Davranışı: Kodlanmış JSON değerinin "boş durumu"na göre alanı atlar. Yani,
null
,""
,{}
,[]
olarak kodlandığında atlanır. - Değişiklik Nedeni: v1'in tanımı Go'nun tip sistemine bağımlıdır. v2, JSON tip sistemini temel alarak daha tutarlı bir davranış sağlar. Örneğin, v1'de
bool
tipindekifalse
değeri atlanırken, v2'defalse
boş olmayan bir JSON değeri olduğu için atlanmaz. v2'de, v1'dekiomitempty
'nin0
veyafalse
'a uygulanan davranışını değiştirmek içinomitzero
seçeneği eklenmiştir. - İlgili Seçenek: v2'de v1 ile aynı davranışı istenirse
json.OmitEmptyWithLegacyDefinition(true)
seçeneği kullanılır.
3. string
Tag Seçeneğinin Davranış Değişikliği
- v1 Davranışı: Sayı, boolean ve string tipindeki alanlara uygulanır. İlgili değeri JSON string'i içine tekrar kodlar (örn:
int(42)
->"42"
). Bileşik tiplerin (slice, map vb.) içindeki değerlere özyinelemeli olarak uygulanmaz. - v2 Davranışı: Yalnızca sayı tiplerine uygulanır ve özyinelemeli olarak uygulanır. Yani,
[]int
gibi slice içindeki sayılar da JSON string'i olarak kodlanır. - Değişiklik Nedeni:
string
seçeneğinin temel kullanım amacı, 64-bit tam sayıların hassasiyet kaybını önlemek için sayıları string olarak ifade etmektir. v1'in davranışı sınırlı ve tutarsızdı. v2, bu temel kullanıma odaklanmış ve davranışı özyinelemeli olarak genişleterek daha kullanışlı hale getirmiştir. - İlgili Seçenek:
json.StringifyWithLegacySemantics(true)
seçeneği ile v1'in davranışı taklit edilebilir.
4. nil
Slice ve Map Marshalling
- v1 Davranışı:
nil
slice'lar venil
map'lernull
olarak Marshall edilir. - v2 Davranışı: Varsayılan olarak
nil
slice'lar[]
(boş array),nil
map'ler{}
(boş object) olarak Marshall edilir. - Değişiklik Nedeni:
nil
Go dilinin bir implementasyon detayıdır ve dile özgü olmayan JSON formatına bunu ifşa etmek arzu edilmez. Boş koleksiyonları temsil eden[]
veya{}
daha evrensel ifadelerdir. - İlgili Seçenek: v2'de
json.FormatNilSliceAsNull(true)
veyajson.FormatNilMapAsNull(true)
seçenekleri aracılığıyla v1 gibinull
olarak Marshall edilebilir.
5. Array Unmarshalling
- v1 Davranışı: Go array'ine (
[N]T
) Unmarshal edilirken, JSON array'inin uzunluğu Go array'inin uzunluğundan farklı olsa bile hata vermez. Uzunluk kısa ise kalan boşluklar sıfır değerlerle doldurulur, uzun ise fazla kısımlar atılır. - v2 Davranışı: JSON array'inin uzunluğu Go array'inin uzunluğu ile tam olarak eşleşmelidir. Aksi takdirde hata oluşur.
- Değişiklik Nedeni: Go'da sabit boyutlu array'lerin uzunluğu çoğu zaman önemli bir anlam taşır. v1'in davranışı, verinin sessizce kaybolmasına neden olabilir. v2, daha katı kurallarla doğruluğu artırmıştır.
- İlgili Seçenek:
json.UnmarshalArrayFromAnyLength(true)
seçeneği ile v1'in davranışı taklit edilebilir.
6. time.Duration
İşleme
- v1 Davranışı:
time.Duration
dahili olarakint64
olarak ele alınır ve nanosaniye cinsinden JSON sayısı olarak kodlanır. - v2 Davranışı:
time.Duration.String()
metodu kullanılarak"1h2m3s"
gibi formatta JSON string'i olarak kodlanır. - Değişiklik Nedeni: Sayısal nanosaniyeler okunabilirliği düşüktür ve
time.Duration
'ın standart string gösterimi daha kullanışlıdır. - İlgili Seçenek:
json:",format:nano"
tag seçeneği veyajson.FormatTimeWithLegacySemantics(true)
seçeneği aracılığıyla v1'in davranışı kullanılabilir.
7. Geçersiz UTF-8 İşleme
- v1 Davranışı: Marshalling/Unmarshalling sırasında string içinde geçersiz UTF-8 byte'ları varsa, Unicode yerine geçme karakteri (
\uFFFD
) ile sessizce değiştirir. - v2 Davranışı: Varsayılan olarak geçersiz UTF-8 ile karşılaşıldığında hata döndürür.
- Değişiklik Nedeni: Veri kaybını önlemek ve daha katı JSON standardına (RFC 7493) uymak içindir.
- İlgili Seçenek:
jsontext.AllowInvalidUTF8(true)
seçeneği ile v1'in davranışı taklit edilebilir.
8. Yinelenen Nesne Üye Adı İşleme
- v1 Davranışı: JSON nesnesi içinde aynı isimde birden fazla üyenin bulunmasına izin verir. Son görünen değer ile üzerine yazar.
- v2 Davranışı: Varsayılan olarak yinelenen üye adı varsa hata döndürür.
- Değişiklik Nedeni: RFC 8259 standardı, yinelenen isimlerin davranışını tanımlamadığı için implementasyondan implementasyona farklılık gösterebilir. Bu, güvenlik açığına neden olabilir. v2, bunu açıkça reddederek doğruluk ve güvenliği artırmıştır.
- İlgili Seçenek:
jsontext.AllowDuplicateNames(true)
seçeneği ile v1'in davranışı taklit edilebilir.
Implementasyon ve Mimari Farklılıkları
- v1:
decode.go
'dakidecodeState
vescanner.go
'daki manuel olarak yazılmış state machine'e büyük ölçüde bağımlıdır. Bu, ayrıştırma mantığı ve anlamsal analizin güçlü bir şekilde birleştiği monolitik bir yapıdır. - v2: Mimarisi daha modüler hale getirilmiştir.
encoding/json/jsontext
: Düşük seviyeli, yüksek performanslı JSON tokenizer (Decoder
) ve encoder (Encoder
) sağlar. Bu paket yalnızca JSON'un sözdizimsel (syntax) yönüne odaklanır.encoding/json/v2
:jsontext
'i temel alarak Go tipleri ile JSON değerleri arasındaki anlamsal (semantic) dönüşümü işler.- Bu ayrım sayesinde sözdizimsel analiz ve anlamsal analiz ayrıştırılarak kodun netliği ve performansı artırılmıştır.
v2'nin Yeni API ve Özellikleri
v2, json.Options
sistemi aracılığıyla oldukça esnek kontrol özellikleri sunar.
json.Options
: Marshalling/Unmarshalling davranışını değiştiren seçenekler kümesidir.json.JoinOptions(...)
: Birden fazla seçeneği tek bir seçenekte birleştirir.WithMarshalers
/WithUnmarshalers
:Marshaler
/Unmarshaler
arayüzünü implemente etmeden belirli tipler için serileştirme/deserileştirme mantığını enjekte etmeye olanak tanıyan güçlü bir özelliktir. Bu, özellikle harici paketlerin tiplerini işlerken faydalıdır.- Yeni Seçenekler:
RejectUnknownMembers
,Deterministic(false)
,FormatNilSliceAsNull
gibi v1'de mümkün olmayan çeşitli davranış kontrolü artık mevcuttur.
Sonuç
encoding/json
v2, v1'in deneyimlerinden yola çıkarak doğruluk, performans ve esnekliği önemli ölçüde artıran modern bir implementasyondur. Varsayılan davranış daha katı hale gelmiş olsa da, gelişmiş Options
sistemi aracılığıyla v1'in tüm davranışlarını tamamen destekler, böylece mevcut kodla uyumluluğu korurken v2'nin avantajları kademeli olarak benimsenebilir.
- Yeni bir proje ise v2'yi varsayılan olarak kullanmak önerilir.
- Mevcut projeler
jsonv1
'i kullanmaya devam edebilir veyajsonv2
'ye geçiş yaparkenDefaultOptionsV1()
aracılığıyla v2'nin katı davranışlarını aşamalı olarak benimseme stratejisini kullanabilir.