Go 1.25 encoding/json/v2 käyttäytymismuutokset ja v1-yhteensopivuuskerroksen analyysi

Go-kielen encoding/json-paketin v2 on uusi toteutus, jonka tavoitteena on parantaa vanhan v1:n useita heikkouksia (johdonmukaisuuden puute, yllättävä käyttäytyminen, suorituskykyongelmat). Se on kokeellinen ominaisuus, joka otetaan käyttöön goexperiment.jsonv2-koontilipun kautta.
Tärkeintä on, että kun v2 on käytössä, v1 toimii yhteensopivuuskerroksena, joka emuloi v1:n käyttäytymistä v2-toteutuksen päällä. Tämä toteutuu v2_v1.go-tiedoston DefaultOptionsV1()-funktion kautta. Toisin sanoen v2 tarjoaa asetukset, joilla v1:n käyttäytyminen voidaan toistaa täydellisesti, ja samalla se esittelee tiukemmat ja ennustettavammat uudet oletuskäyttäytymiset.
v2:n pääasialliset tavoitteet ovat seuraavat:
- Tarkkuuden ja ennustettavuuden parantaminen: Oletuksena sovelletaan tiukempia sääntöjä (esimerkiksi isot ja pienet kirjaimet erottava vertailu, kielletyt kaksoiskaviot), mikä vähentää odottamatonta käyttäytymistä.
- Suorituskyvyn parantaminen: Jäsennys- ja koodausmoottori on suunniteltu uudelleen tehokkuuden lisäämiseksi.
- Joustavuuden ja hallinnan laajentaminen: Yksityiskohtainen asetusjärjestelmä mahdollistaa kehittäjille JSON-käsittelyn hienojakoisen hallinnan.
Keskeiset merkitys- ja käyttäytymiserot
Erot v1:n ja v2:n välillä on koottu kohdittain, pääpainon ollessa v2_test.go-tiedostossa.
1. Kenttänimien vastaavuus (isot ja pienet kirjaimet)
- v1-käyttäytyminen: Kun JSON-olion jäseniä unmarshalloidaan Go-rakenteen kenttiin, vastaavuus tehdään kirjainkoosta riippumatta (case-insensitive). Sekä
"FirstName"että"firstname"kartoittuvat kenttäänFirstName. - v2-käyttäytyminen: Oletuksena vastaavuus on kirjainkokoherkkä (case-sensitive), ja kenttään kartoittuu vain tarkasti täsmäävä nimi.
- Muutoksen syy: Kirjainkoosta riippumaton vastaavuus voi aiheuttaa odottamatonta käyttäytymistä, ja se heikentää suorituskykyä käsiteltäessä kenttiä, jotka eivät täsmää. v2 valitsi oletukseksi selkeämmän ja ennustettavamman käyttäytymisen.
- Liittyvät asetukset: v2:ssa voidaan käyttää
json:"...,case:ignore"-tagiasetusta, jolla kirjainkoosta riippumaton vastaavuus otetaan eksplisiittisesti käyttöön kentittäin, taijson.MatchCaseInsensitiveNames(true)-asetusta, joka otetaan käyttöön globaalisti.
2. omitempty-tagiasetuksen merkityksen muutos
- v1-käyttäytyminen: Kenttä jätetään pois Go-arvon "tyhjän tilan" perusteella. Tyhjä tila tarkoittaa tässä arvoja
false,0,nil-osoitinta tai -liitäntää sekä pituudeltaan nollaa olevaa taulukkoa, viipaletta, karttaa tai merkkijonoa. - v2-käyttäytyminen: Kenttä jätetään pois koodatun JSON-arvon "tyhjän tilan" perusteella. Eli jos arvo koodautuu muotoon
null,"",{}tai[], kenttä jätetään pois. - Muutoksen syy: v1:n määritelmä on sidoksissa Go-tyyppijärjestelmään. v2 perustuu JSON-tyyppijärjestelmään ja tarjoaa siten johdonmukaisemman käyttäytymisen. Esimerkiksi v1:ssä
bool-tyypin arvofalsejätetään pois, mutta v2:ssafalseon JSON-arvo, joka ei ole tyhjä, eikä sitä jätetä pois. v2:ssa on lisättyomitzero-asetus, jolla voidaan korvata v1:nomitempty-käyttäytyminen, joka koski arvoja0jafalse. - Liittyvät asetukset: Jos halutaan v1:n kanssa identtinen käyttäytyminen, käytetään asetusta
json.OmitEmptyWithLegacyDefinition(true).
3. string-tagiasetuksen käyttäytymisen muutos
- v1-käyttäytyminen: Sovelletaan kenttiin, joiden tyyppi on numero, totuusarvo tai merkkijono. Arvo koodataan uudelleen JSON-merkkijonon sisälle (esimerkiksi
int(42)->"42"). Yhdistettyjen tyyppien (viipaleet, kartat jne.) sisäisiin arvoihin ei sovelleta asetusta rekursiivisesti. - v2-käyttäytyminen: Sovelletaan vain numerotyyppeihin, ja asetus on rekursiivinen. Eli myös esimerkiksi
[]int-viipaleen sisäiset numerot koodataan kaikki JSON-merkkijonoiksi. - Muutoksen syy:
string-asetuksen pääasiallinen käyttötarkoitus on estää 64-bittisten kokonaislukujen tarkkuuden menetys esittämällä numerot merkkijonoina. v1:n käyttäytyminen oli rajoittunutta ja johdonmukaisuudeltaan puutteellista. v2 keskittyy tähän keskeiseen käyttötarkoitukseen ja laajentaa käyttäytymistä rekursiivisesti, jolloin asetuksesta tuli hyödyllisempi. - Liittyvät asetukset: v1:n käyttäytymistä voidaan jäljitellä asetuksella
json.StringifyWithLegacySemantics(true).
4. nil-viipaleiden ja -karttojen marshalointi
- v1-käyttäytyminen:
nil-viipale janil-kartta marshalloidaan muotoonnull. - v2-käyttäytyminen: Oletuksena
nil-viipale marshalloidaan muotoon[](tyhjä taulukko) janil-kartta muotoon{}(tyhjä olio). - Muutoksen syy:
nilon Go-kielen toteutuksen yksityiskohta, eikä sen paljastaminen kielestä riippumattomassa JSON-muodossa ole toivottavaa. Tyhjiä kokoelmia esittävät[]ja{}ovat yleisempiä ilmaisuja. - Liittyvät asetukset: v2:ssa voidaan marshalloida v1:n tapaan
null-arvoksi käyttämällä asetuksiajson.FormatNilSliceAsNull(true)taijson.FormatNilMapAsNull(true).
5. Taulukon unmarshalointi
- v1-käyttäytyminen: Kun JSON-taulukko unmarshalloidaan Go-taulukkoon (
[N]T), virhettä ei synny, vaikka JSON-taulukon pituus poikkeaisi Go-taulukon pituudesta. Jos JSON-taulukko on lyhyempi, ylimääräinen tila täytetään nollla-arvoilla, ja jos se on pidempi, ylimenevä osa hylätään. - v2-käyttäytyminen: JSON-taulukon pituuden on täsmättävä tarkalleen Go-taulukon pituuteen. Muussa tapauksessa syntyy virhe.
- Muutoksen syy: Go-kielessä kiinteäkokoisen taulukon pituudella on usein merkittävä merkitys. v1:n käyttäytyminen voi aiheuttaa datan äänetöntä katoamista. v2 nostaa tarkkuutta tiukemmalla säännöllä.
- Liittyvät asetukset: v1:n käyttäytymistä voidaan jäljitellä asetuksella
json.UnmarshalArrayFromAnyLength(true).
6. time.Duration-tyypin käsittely
- v1-käyttäytyminen:
time.Durationkäsitellään sisäisestiint64-tyyppinä, ja se koodataan nanosekuntiyksikössä olevaksi JSON-numeroksi. - v2-käyttäytyminen: Koodaus tehdään
time.Duration.String()-metodin avulla JSON-merkkijonona muodossa, kuten"1h2m3s". - Muutoksen syy: Nanosekuntimuotoiset numerot ovat vaikeasti luettavia, ja
time.Duration-tyypin vakiomerkkijonoesitys on hyödyllisempi. - Liittyvät asetukset: v1:n käyttäytymisen voi ottaa käyttöön tagiasetuksella
json:",format:nano"tai asetuksellajson.FormatTimeWithLegacySemantics(true).
7. Virheellisen UTF-8:n käsittely
- v1-käyttäytyminen: Marshalloinnin ja unmarshaloinnin aikana merkkijonossa olevat virheelliset UTF-8-tavut korvataan äänettömästi Unicode-korvaavalla merkillä (
\uFFFD). - v2-käyttäytyminen: Oletuksena virheellinen UTF-8 aiheuttaa virheen.
- Muutoksen syy: Tarkoituksena on estää datan äänetön vioittuminen ja noudattaa tiukempaa JSON-standardia (RFC 7493).
- Liittyvät asetukset: v1:n käyttäytymistä voidaan jäljitellä asetuksella
jsontext.AllowInvalidUTF8(true).
8. Kaksoiskappaleiden käsittely objektin jäsennimissä
- v1-käyttäytyminen: JSON-oliossa sallitaan saman nimisten jäsenten esiintyminen useaan kertaan. Viimeisenä esiintyvä arvo ylikirjoittaa aiemmat.
- v2-käyttäytyminen: Oletuksena kaksoiskappaleena esiintyvä jäsennimi aiheuttaa virheen.
- Muutoksen syy: RFC 8259 -standardi ei määrittele kaksoiskappaleiden käsittelyä, joten eri toteutukset voivat toimia eri tavoin. Tämä voi olla tietoturvahaavoittuvuuden lähde. v2 hylkää ne eksplisiittisesti, mikä parantaa tarkkuutta ja tietoturvaa.
- Liittyvät asetukset: v1:n käyttäytymistä voidaan jäljitellä asetuksella
jsontext.AllowDuplicateNames(true).
Toteutus- ja arkkitehtuurierot
- v1: Luottaa voimakkaasti
decode.go-tiedostondecodeState-rakenteeseen jascanner.go-tiedoston käsin kirjoitettuun tilakoneeseen. Tämä on jäsennyslogiikan ja semanttisen analyysin tiukasti yhdistävä monoliittinen rakenne. - v2: Arkkitehtuuri on modulaarisempi.
encoding/json/jsontext: Tarjoaa matalan tason, suorituskykyisen JSON-tokenisoijan (Decoder) ja kooderin (Encoder). Tämä paketti keskittyy ainoastaan JSON-syntaksin puoleen.encoding/json/v2: Käsitteleejsontext-paketin pohjalta Go-tyyppien ja JSON-arvojen välisen semanttisen muunnoksen.- Tämän jaottelun ansiosta syntaksianalyysi ja semanttinen analyysi on erotettu toisistaan, mikä on parantanut koodin selkeyttä ja suorituskykyä.
v2:n uudet API:t ja ominaisuudet
v2 tarjoaa erittäin joustavia hallintaominaisuuksia json.Options-asetusjärjestelmän kautta.
json.Options: Joukko asetuksia, jotka muuttavat marshalointi- ja unmarshalointikäyttäytymistä.json.JoinOptions(...): Yhdistää useita asetuksia yhdeksi.WithMarshalers/WithUnmarshalers: Tehokas ominaisuus, jolla serialisointi- ja deserialisointilogiikka voidaan lisätä tietylle tyypille ilman, että tyyppi toteuttaaMarshaler- taiUnmarshaler-rajapintaa. Tämä on erityisen hyödyllistä, kun käsitellään ulkoisten pakettien tyyppejä.- Uudet asetukset:
RejectUnknownMembers,Deterministic(false),FormatNilSliceAsNullja muut mahdollistavat käyttäytymisen hallinnan tavalla, joka ei ollut mahdollinen v1:ssä.
Yhteenveto
encoding/json v2 on nykyaikainen toteutus, joka perustuu v1:n kokemuksiin ja parantaa merkittävästi tarkkuutta, suorituskykyä ja joustavuutta. Oletuskäyttäytyminen on tiukempi, mutta hienostuneen Options-järjestelmän ansiosta v1:n kaikki käyttäytymiset voidaan toteuttaa täysin, joten olemassa oleva koodi säilyy yhteensopivana ja v2:n etuja voidaan ottaa käyttöön vaiheittain.
- Uusi projekti kannattaa toteuttaa oletuksena v2:lla.
- Olemassa olevat projektit voivat joko käyttää
jsonv1-pakettia sellaisenaan tai siirtyäjsonv2-pakettiin ja ottaa v2:n tiukemman käyttäytymisen vaiheittain käyttöönDefaultOptionsV1()-funktion avulla.