---
id: 61f2009278a5f7366f79395da59447cf
author: lemonmint
title: Analýza zmien správania encoding/json/v2 v Go 1.25 a vrstvy kompatibility s v1
description: Porovnávame case-sensitive párovanie, zmeny sémantiky omitempty/omitzero, serializáciu nil slice/map a možnosti encoding/json/v2, ktorý bol zavedený ako experimentálna funkcia Go 1.25 (goexperiment.jsonv2).
language: sk
date: 2025-06-20T05:38:20.100520237Z
path: /blog/posts/go-1-25-encoding-json-v1-vs-v2-z74a36b08
category: release
---

Balík `encoding/json` v2 v Go je novou implementáciou, ktorej cieľom je odstrániť viaceré nedostatky pôvodnej verzie v1 (nedostatočná konzistentnosť, prekvapivé správanie, problémy s výkonom). Ide o experimentálnu funkciu, ktorá sa aktivuje prostredníctvom build tagu `goexperiment.jsonv2`.

Najdôležitejšou skutočnosťou je, že **ak je v2 aktivované, v1 funguje ako kompatibilná vrstva, ktorá na implementácii v2 emuluje správanie v1**. Deje sa tak prostredníctvom funkcie `DefaultOptionsV1()` v súbore `v2_v1.go`. To znamená, že v2 poskytuje možnosti, ktorými možno správanie v1 úplne reprodukovať, a zároveň ponúka prísnejšie a predvídateľnejšie nové predvolené správanie.

Hlavné ciele v2 sú nasledujúce:

1. **Zlepšenie správnosti a predvídateľnosti**: Predvolene uplatňuje prísnejšie pravidlá (napríklad rozlišovanie veľkých a malých písmen, zákaz duplicitných kľúčov), čím znižuje výskyt neočakávaného správania.
2. **Zlepšenie výkonu**: Parsovací a kódovací engine bol prepracovaný s cieľom zvýšiť efektivitu.
3. **Rozšírenie flexibility a kontroly**: Zavádza podrobný systém možností, ktorý vývojárom umožňuje jemne riadiť spracovanie JSON.

---

## Hlavné významové a behaviorálne rozdiely

Rozdiely medzi v1 a v2 sú zhrnuté po položkách so zameraním na súbor `v2_test.go`.

### 1. Porovnávanie názvov polí (rozlišovanie veľkých a malých písmen)

- **Správanie v1**: Pri unmarshalovaní členov JSON objektu do polí štruktúry v Go sa **ignoruje veľkosť písmen (case-insensitive)**. Ako `FirstName`, tak `firstname` sa namapujú na pole `FirstName`.
- **Správanie v2**: Predvolene **rozlišuje veľkosť písmen (case-sensitive)** a mapuje iba polia, ktoré sa presne zhodujú.
- **Dôvod zmeny**: Porovnávanie bez ohľadu na veľkosť písmen môže viesť k neočakávanému správaniu a pri spracovaní nezhodných polí spôsobuje zníženie výkonu. v2 prijíma jasnejšie a predvídateľnejšie správanie ako predvolené.
- **Súvisiace možnosti**: V v2 možno pomocou tagu `json:"...,case:ignore"` explicitne povoliť ignorovanie veľkosti písmen pre jednotlivé polia alebo globálne aplikovať `json.MatchCaseInsensitiveNames(true)`.

### 2. Zmena významu voľby `omitempty`

- **Správanie v1**: Polia sa vynechávajú na základe "prázdneho stavu" hodnoty v Go. "Prázdnym stavom" sa rozumie `false`, `0`, `nil` ukazovateľ/rozhranie a pole, reťazec, slice alebo mapa s dĺžkou 0.
- **Správanie v2**: Polia sa vynechávajú na základe "prázdneho stavu" zakódovanej hodnoty JSON. To znamená, že sa vynechajú, ak sú zakódované ako `null`, `""`, `{}` alebo `[]`.
- **Dôvod zmeny**: Definícia v1 závisí od typového systému Go. v2 vychádza z typového systému JSON a poskytuje tak konzistentnejšie správanie. Napríklad v v1 sa hodnota `false` typu `bool` vynechá, kým v v2 sa nevynechá, pretože `false` je neprázdna hodnota JSON. V v2 možno pridaním voľby `omitzero` nahradiť správanie v1, pri ktorom `omitempty` pôsobilo na `0` alebo `false`.
- **Súvisiace možnosti**: Ak sa v v2 požaduje správanie zhodné s v1, použije sa voľba `json.OmitEmptyWithLegacyDefinition(true)`.

### 3. Zmena správania voľby `string`

- **Správanie v1**: Použije sa pri poliach číselného, logického a reťazcového typu. Príslušná hodnota sa znovu zakóduje do reťazca JSON (napríklad `int(42)` -> `"42"`). Na hodnoty vnútri zložených typov (slice, mapa a pod.) sa nevzťahuje rekurzívne.
- **Správanie v2**: **Vzťahuje sa iba na číselné typy** a uplatňuje sa rekurzívne. To znamená, že aj čísla vnútri slice, napríklad `[]int`, sa zakódujú ako reťazce JSON.
- **Dôvod zmeny**: Hlavným účelom voľby `string` je vyjadriť čísla ako reťazce, aby sa predišlo strate presnosti 64-bitových celých čísel. Správanie v1 bolo obmedzené a málo konzistentné. v2 sa sústreďuje na tento kľúčový účel a rozširuje správanie rekurzívne, čím je užitočnejšie.
- **Súvisiace možnosti**: Správanie v1 možno napodobniť voľbou `json.StringifyWithLegacySemantics(true)`.

### 4. Marshalovanie hodnôt `nil` slice a mapy

- **Správanie v1**: Hodnoty `nil` slice a `nil` mapa sa marshalujú ako `null`.
- **Správanie v2**: Predvolene sa `nil` slice marshaluje ako `[]` (prázdne pole) a `nil` mapa ako `{}` (prázdny objekt).
- **Dôvod zmeny**: `nil` je implementačný detail jazyka Go a sprístupňovať ho v jazykovo neutrálnom formáte JSON nie je vhodné. Zápisy `[]` a `{}`, ktoré reprezentujú prázdne kolekcie, sú univerzálnejším vyjadrením.
- **Súvisiace možnosti**: V v2 možno pomocou `json.FormatNilSliceAsNull(true)` alebo `json.FormatNilMapAsNull(true)` marshalovať ako `null`, rovnako ako v v1.

### 5. Unmarshalovanie polí

- **Správanie v1**: Pri unmarshalovaní do poľa Go (`[N]T`) nevyvolá dĺžka poľa JSON chybu, ak sa líši od dĺžky poľa Go. Ak je pole kratšie, zvyšné miesto sa vyplní nulovými hodnotami, a ak je dlhšie, prebytok sa zahodí.
- **Správanie v2**: Dĺžka poľa JSON musí **presne zodpovedať** dĺžke poľa Go. V opačnom prípade vznikne chyba.
- **Dôvod zmeny**: V Go má dĺžka polí pevnej veľkosti často zásadný význam. Správanie v1 môže spôsobiť tiché straty dát. v2 prísnejšími pravidlami zvyšuje správnosť.
- **Súvisiace možnosti**: Správanie v1 možno napodobniť voľbou `json.UnmarshalArrayFromAnyLength(true)`.

### 6. Spracovanie `time.Duration`

- **Správanie v1**: `time.Duration` sa interne považuje za `int64` a kóduje sa ako číslo JSON v nanosekundách.
- **Správanie v2**: Kóduje sa ako reťazec JSON vo formáte, napríklad `"1h2m3s"`, pomocou metódy `time.Duration.String()`.
- **Dôvod zmeny**: Číselné nanosekundy sa ťažšie čitajú a štandardné reťazcové vyjadrenie `time.Duration` je užitočnejšie.
- **Súvisiace možnosti**: Správanie v1 možno použiť prostredníctvom tagu `json:",format:nano"` alebo voľby `json.FormatTimeWithLegacySemantics(true)`.

### 7. Spracovanie neplatného UTF-8

- **Správanie v1**: Pri marshalovaní/unmarshalovaní sa neplatné bajty UTF-8 v reťazcoch **ticho nahradia** Unicode náhradným znakom (`\uFFFD`).
- **Správanie v2**: Predvolene pri narazení na neplatný UTF-8 **vracia chybu**.
- **Dôvod zmeny**: Cieľom je zabrániť tichému poškodeniu dát a dodržiavať prísnejší štandard JSON (RFC 7493).
- **Súvisiace možnosti**: Správanie v1 možno napodobniť voľbou `jsontext.AllowInvalidUTF8(true)`.

### 8. Spracovanie duplicitných názvov členov objektu

- **Správanie v1**: V objekte JSON sa povoľuje výskyt členov s rovnakým názvom. Posledná hodnota prepíše predchádzajúce.
- **Správanie v2**: Predvolene pri výskyte duplicitného názvu člena **vracia chybu**.
- **Dôvod zmeny**: Štandard RFC 8259 nedefinuje správanie pri duplicitných názvoch, preto sa implementácie môžu líšiť. Môže to byť príčinou bezpečnostných zraniteľností. v2 to explicitne odmieta, čím zvyšuje správnosť a bezpečnosť.
- **Súvisiace možnosti**: Správanie v1 možno napodobniť voľbou `jsontext.AllowDuplicateNames(true)`.

---

## Rozdiely v implementácii a architektúre

- **v1**: Výrazne sa spolieha na `decodeState` v súbore `decode.go` a na ručne napísaný stavový automat (state machine) v súbore `scanner.go`. Ide o monolitickú štruktúru, v ktorej sú parsovacia logika a sémantická analýza silne previazané.
- **v2**: Architektúra je modulárnejšia.
  - **`encoding/json/jsontext`**: Poskytuje nízkoúrovňový, vysoko výkonný tokenizér JSON (`Decoder`) a kodér (`Encoder`). Tento balík sa sústreďuje výhradne na syntaktickú stránku JSON.
  - **`encoding/json/v2`**: Na základe `jsontext` zabezpečuje sémantickú konverziu medzi typmi Go a hodnotami JSON.
  - Vďaka tomuto oddeleniu sú syntaktická a sémantická analýza oddelené, čo zlepšuje prehľadnosť kódu a výkon.

---

## Nové API a funkcie v2

v2 poskytuje veľmi flexibilné riadenie prostredníctvom systému `json.Options`.

- **`json.Options`**: Súbor možností, ktoré menia správanie pri marshalovaní/unmarshalovaní.
- **`json.JoinOptions(...)`**: Zlúči viacero možností do jednej.
- **`WithMarshalers` / `WithUnmarshalers`**: Výkonná funkcia, ktorá umožňuje vložiť logiku serializácie/deserializácie pre konkrétny typ bez implementácie rozhraní `Marshaler`/`Unmarshaler`. Je obzvlášť užitočná pri spracovaní typov z externých balíkov.
- **Nové možnosti**: `RejectUnknownMembers`, `Deterministic(false)`, `FormatNilSliceAsNull` a ďalšie umožňujú riadenie správania, ktoré v v1 nebolo možné.

---

## Záver

`encoding/json` v2 je moderná implementácia, ktorá na základe skúseností s v1 výrazne zlepšuje **správnosť, výkon a flexibilitu**. Predvolené správanie sa sprísnilo, no prostredníctvom sofistikovaného systému `Options` možno plne podporiť všetko správanie v1, vďaka čomu sa zachová kompatibilita s existujúcim kódom a výhody v2 je možné zavádzať postupne.

- **Pre nové projekty** sa odporúča používať v2 ako predvolenú možnosť.
- **Existujúce projekty** môžu buď ponechať `jsonv1`, alebo prejsť na `jsonv2` a postupne zavádzať prísnejšie správanie v2 pomocou `DefaultOptionsV1()`.
