---
id: 61f2009278a5f7366f79395da59447cf
author: lemonmint
title: Go 1.25 encoding/json/v2 működésbeli változásai és a v1 kompatibilitási réteg elemzése
description: A Go 1.25 kísérleti funkciójaként (goexperiment.jsonv2) bevezetett encoding/json/v2 esetében a kis- és nagybetű-érzéketlen egyeztetést, az omitempty/omitzero jelentésének megváltozását, valamint a nil szeleteknek és leképezéseknek (map) történő szerializálást és az ehhez kapcsolódó beállításokat hasonlítjuk össze.
language: hu
date: 2025-06-20T05:38:20.100520237Z
path: /blog/posts/go-1-25-encoding-json-v1-vs-v2-z74a36b08
category: release
---

A Go `encoding/json` csomagjának v2 verziója a v1 több hátrányának (következetlenség, meglepő viselkedés, teljesítményproblémák) orvoslására létrehozott új megvalósítás. Ez a `goexperiment.jsonv2` build címke segítségével aktiválható kísérleti funkció.

A legfontosabb megállapítás, hogy **ha a v2 aktív, a v1 a v2 megvalósítása fölött működő kompatibilitási rétegként viselkedik, amely emulálja a v1 működését**. Ez a `v2_v1.go` fájl `DefaultOptionsV1()` függvényén keresztül valósul meg. Vagyis a v2 olyan opciókat biztosít, amelyekkel a v1 viselkedése tökéletesen reprodukálható, ugyanakkor szigorúbb és kiszámíthatóbb új alapértelmezett viselkedést kínál.

A v2 fő céljai a következők:

1. **A pontosság és a kiszámíthatóság javítása**: Alapértelmezetten szigorúbb szabályokat alkalmaz (például megkülönbözteti a kis- és nagybetűket, tiltja az ismétlődő kulcsokat), ezzel csökkenti a váratlan viselkedést.
2. **Teljesítményjavítás**: A feldolgozó és kódoló motort átalakították a hatékonyság növelése érdekében.
3. **Nagyobb rugalmasság és irányítási lehetőség**: Részletes opciórendszert vezet be, amely lehetővé teszi a fejlesztők számára, hogy finoman szabályozzák a JSON-feldolgozás módját.

---

## Főbb jelentésbeli és viselkedésbeli különbségek

A `v2_test.go` fájlra támaszkodva, pontokba szedve foglaltuk össze a v1 és a v2 viselkedése közötti különbségeket.

### 1. Mezőnevek illesztése (kis- és nagybetű megkülönböztetése)

- **v1 viselkedés**: Amikor a JSON objektum tagjait Go struct mezőkbe demarshaláljuk, **a kis- és nagybetűket figyelmen kívül hagyva (case-insensitive)** illeszt. A `"FirstName"` és a `"firstname"` is a `FirstName` mezőhöz kerül.
- **v2 viselkedés**: Alapértelmezetten **megkülönbözteti a kis- és nagybetűket (case-sensitive)**, és csak a pontosan egyező mezőket állítja be.
- **A változtatás oka**: A kis- és nagybetűk figyelmen kívül hagyása meglepő viselkedést okozhat, és a nem illeszkedő mezők kezelésekor teljesítménycsökkenést idézhet elő. A v2 a világosabb és kiszámíthatóbb viselkedést tette alapértelmezetté.
- **Kapcsolódó opciók**: A v2-ben a `json:"...,case:ignore"` tagopcióval mezőnként kifejezetten engedélyezhető a kis- és nagybetűk figyelmen kívül hagyása, vagy globálisan alkalmazható a `json.MatchCaseInsensitiveNames(true)` opció.

### 2. Az `omitempty` tagopció jelentésének megváltozása

- **v1 viselkedés**: A mezőt a Go-érték „üres állapota” alapján hagyja ki. Ez alatt a `false`, a `0`, a `nil` mutató/interfész, valamint a nulla hosszúságú tömb/szelet/map/string értendő.
- **v2 viselkedés**: A mezőt a kódolt JSON-érték „üres állapota” alapján hagyja ki. Vagyis akkor marad ki, ha `null`, `""`, `{}` vagy `[]` formában kódolódik.
- **A változtatás oka**: A v1 definíciója a Go típusrendszeréhez kötött. A v2 a JSON típusrendszerét veszi alapul, ezáltal következetesebb viselkedést biztosít. Például a v1-ben a `bool` típus `false` értéke kimarad, míg a v2-ben a `false` nem üres JSON-érték, ezért nem marad ki. A v2 bevezeti az `omitzero` opciót, amellyel a v1 `omitempty` `0`-ra vagy `false`-ra vonatkozó viselkedése helyettesíthető.
- **Kapcsolódó opciók**: Ha a v1-gyel azonos viselkedést szeretnénk v2-ben, használjuk a `json.OmitEmptyWithLegacyDefinition(true)` opciót.

### 3. A `string` tagopció viselkedésének megváltozása

- **v1 viselkedés**: Számok, logikai értékek és string típusú mezőkre alkalmazható. Az értéket újra kódolja egy JSON-stringbe (például `int(42)` -> `"42"`). Összetett típusok (szeletek, mapek stb.) belső értékeire nem alkalmazza rekurzívan.
- **v2 viselkedés**: **Kizárólag numerikus típusokra alkalmazható**, és rekurzívan érvényesül. Vagyis a `[]int` típusú szeletben lévő számok is mind JSON-stringként kerülnek kódolásra.
- **A változtatás oka**: A `string` opció fő célja, hogy a 64 bites egészek pontosságvesztését elkerülje azáltal, hogy a számokat stringként ábrázolja. A v1 viselkedése korlátozott volt és következetlen. A v2 erre a fő felhasználásra összpontosít, és a viselkedést rekurzívan kiterjesztve hasznosabbá tette.
- **Kapcsolódó opciók**: A `json.StringifyWithLegacySemantics(true)` opcióval utánozható a v1 viselkedése.

### 4. `nil` szeletek és mapek marshalálása

- **v1 viselkedés**: A `nil` szeletek és a `nil` mapek `null` értékként marshalálódnak.
- **v2 viselkedés**: Alapértelmezetten a `nil` szeletek `[]` (üres tömb), a `nil` mapek `{}` (üres objektum) formában marshalálódnak.
- **A változtatás oka**: A `nil` a Go nyelv implementációs részlete, és nem célszerű ezt a nyelvtől független JSON-formátumban megjeleníteni. Az üres gyűjteményeket jelölő `[]` és `{}` általánosabb ábrázolások.
- **Kapcsolódó opciók**: A v2-ben a `json.FormatNilSliceAsNull(true)` vagy a `json.FormatNilMapAsNull(true)` opcióval érhető el, hogy a v1-hez hasonlóan `null` értékként marshalálódjanak.

### 5. Tömbök demarshalálása

- **v1 viselkedés**: Go tömbbe (`[N]T`) történő demarshaláláskor a JSON-tömb hossza eltérhet a Go tömb hosszától anélkül, hogy hibát okozna. Ha a JSON-tömb rövidebb, a fennmaradó helyeket nulla értékekkel tölti fel, ha hosszabb, a többletet eldobja.
- **v2 viselkedés**: A JSON-tömb hosszának **pontosan meg kell egyeznie** a Go tömb hosszával. Ellenkező esetben hiba keletkezik.
- **A változtatás oka**: Go-ban a fix méretű tömbök hossza gyakran fontos jelentéssel bír. A v1 viselkedése csendes adatvesztést okozhat. A v2 szigorúbb szabályokkal növelte a pontosságot.
- **Kapcsolódó opciók**: A `json.UnmarshalArrayFromAnyLength(true)` opcióval utánozható a v1 viselkedése.

### 6. A `time.Duration` kezelése

- **v1 viselkedés**: A `time.Duration` belsőleg `int64`-ként kezelődik, és nanoszekundumos JSON-számként kódolódik.
- **v2 viselkedés**: A `time.Duration.String()` metódust használva, `"1h2m3s"` típusú formátumú JSON-stringként kódolódik.
- **A változtatás oka**: A nyers nanoszekundumos számok nehezen olvashatók, a `time.Duration` szabványos stringes ábrázolása pedig hasznosabb.
- **Kapcsolódó opciók**: A `json:",format:nano"` tagopcióval vagy a `json.FormatTimeWithLegacySemantics(true)` opcióval használható a v1 viselkedése.

### 7. Érvénytelen UTF-8 kezelése

- **v1 viselkedés**: Marshalálás/demarshalálás során, ha egy stringben érvénytelen UTF-8 bájt található, a rendszer azt csendben a Unicode pótkarakterre (`\uFFFD`) cseréli.
- **v2 viselkedés**: Alapértelmezetten hibát ad vissza, ha érvénytelen UTF-8 találkozik.
- **A változtatás oka**: Az adatok csendes sérülésének megelőzése, valamint a szigorúbb JSON-szabvány (RFC 7493) követése.
- **Kapcsolódó opciók**: A `jsontext.AllowInvalidUTF8(true)` opcióval utánozható a v1 viselkedése.

### 8. Ismétlődő objektumtag-nevek kezelése

- **v1 viselkedés**: Megengedi, hogy egy JSON-objektumban azonos nevű tagok ismétlődjenek. Az utolsó megjelenő érték felülírja a korábbiakat.
- **v2 viselkedés**: Alapértelmezetten hibát ad vissza, ha ismétlődő tagnév található.
- **A változtatás oka**: Az RFC 8259 szabvány nem határozza meg az ismétlődő nevek viselkedését, így a megvalósítások eltérően működhetnek. Ez biztonsági sebezhetőség forrása lehet. A v2 kifejezetten elutasítja ezeket, ezzel növelve a pontosságot és a biztonságot.
- **Kapcsolódó opciók**: A `jsontext.AllowDuplicateNames(true)` opcióval utánozható a v1 viselkedése.

---

## Megvalósítási és architekturális különbségek

- **v1**: Nagymértékben támaszkodik a `decode.go` fájlban lévő `decodeState`-re és a `scanner.go` fájlban kézzel írt állapotgépre (state machine). Ez egy monolitikus szerkezet, ahol a feldolgozási logika és a szemantikai elemzés szorosan összefonódik.
- **v2**: Az architektúra moduláris:
  - **`encoding/json/jsontext`**: Alacsony szintű, nagy teljesítményű JSON-tokenizálót (`Decoder`) és kódolót (`Encoder`) biztosít. Ez a csomag kizárólag a JSON szintaktikai oldalára koncentrál.
  - **`encoding/json/v2`**: A `jsontext`-re építve kezeli a Go típusok és a JSON-értékek közötti szemantikai átalakítást.
  - Ez a szétválasztás elkülöníti a szintaktikai és a szemantikai elemzést, ami javítja a kód átláthatóságát és a teljesítményt.

---

## A v2 új API-ja és funkciói

A v2 a `json.Options` rendszeren keresztül rendkívül rugalmas vezérlési lehetőségeket biztosít.

- **`json.Options`**: A marshalálási/demarshalálási viselkedést módosító opciók halmaza.
- **`json.JoinOptions(...)`**: Több opciót egyesít egyetlen opcióba.
- **`WithMarshalers` / `WithUnmarshalers`**: Hatékony funkció, amellyel egy adott típushoz a `Marshaler`/`Unmarshaler` interfész implementálása nélkül injektálható szerializációs/deszerializációs logika. Ez különösen hasznos külső csomagok típusainak kezelésekor.
- **Új opciók**: Az `RejectUnknownMembers`, `Deterministic(false)`, `FormatNilSliceAsNull` és más opciók olyan viselkedésvezérlést tesznek lehetővé, amely v1-ben nem volt elérhető.

---

## Következtetés

Az `encoding/json` v2 a v1 tapasztalataira építve jelentősen javítja a **pontosságot, a teljesítményt és a rugalmasságot**, és modern megvalósítást nyújt. Az alapértelmezett viselkedés szigorúbbá vált, de a kifinomult `Options` rendszerrel a v1 összes viselkedése teljes mértékben támogatott, így a meglévő kóddal való kompatibilitás megmarad, és a v2 előnyei fokozatosan bevezethetők.

- **Új projekt** esetén érdemes alapértelmezettként a v2-t használni.
- **Meglévő projektek** használhatják változatlanul a `jsonv1`-et, vagy migrálhatnak `jsonv2`-re úgy, hogy a `DefaultOptionsV1()` segítségével fokozatosan vezetik be a v2 szigorúbb viselkedését.
