Миграция со стандартной библиотеки
cybergodev/json на 100% совместим со стандартной библиотекой encoding/json — достаточно заменить путь import, и существующий код компилируется и работает без каких-либо изменений (незначительные граничные различия из-за стандартной проверки ввода — в разделе Различия в поведении ниже). Эта страница поможет выполнить миграцию и узнать о дополнительных возможностях, доступных после неё.
Миграция в три шага
Установка:
bashgo get github.com/cybergodev/jsonЗамена import: замените
"encoding/json"на"github.com/cybergodev/json".go// До миграции import "encoding/json" // После миграции import "github.com/cybergodev/json"Готово: компиляция проходит, весь существующий код не требует изменений.
Полностью совместимые API
В таблице ниже приведено соответствие encoding/json и cybergodev/json:
| encoding/json | cybergodev/json | Примечание |
|---|---|---|
Marshal(v) | Marshal(v, cfg...) | Совместимая сигнатура, дополнительный необязательный параметр cfg |
Unmarshal(data, &v) | Unmarshal(data, &v, cfg...) | Аналогично |
MarshalIndent(v, prefix, indent) | То же имя | Полная совместимость |
Compact(dst, src) | То же имя | Полная совместимость |
Indent(dst, src, prefix, indent) | То же имя | Полная совместимость |
HTMLEscape(dst, src) | То же имя | Полная совместимость |
Valid(data) | Valid(data, cfg...) | Совместимая сигнатура |
NewEncoder(w) | NewEncoder(w, cfg...) | Совместимая сигнатура |
NewDecoder(r) | NewDecoder(r, cfg...) | Совместимая сигнатура |
Number | Number | Совместимый тип (String/Int64/Float64/MarshalJSON сохранены) |
Delim | Delim | Совместимый тип (String() сохранён) |
Token | Token | Совместимый тип |
Совместимость Encoder и Decoder на уровне методов также полная — потоковый код после миграции не требует изменений:
| Метод | Принадлежность | Совместимость |
|---|---|---|
Encode(v) / SetIndent(prefix, indent) / SetEscapeHTML(on) | *Encoder | Полная |
Decode(v) / Token() / More() / Buffered() / InputOffset() | *Decoder | Полная |
UseNumber() / DisallowUnknownFields() | *Decoder | Полная |
Типы ошибок также соответствуют один к одному: код, полагающийся на errors.As / утверждение типа, работает напрямую — SyntaxError, UnmarshalTypeError, InvalidUnmarshalError, MarshalerError, UnsupportedTypeError, UnsupportedValueError существуют и ведут себя одинаково (подробнее см. Типы ошибок).
Поля локализации в структурах ошибок также сохранены по одному — код, полагающийся на них для локализации сбоев или классификационной статистики, не требует изменений:
| Тип | Поле | Тип | Описание |
|---|---|---|---|
SyntaxError | Offset | int64 | Число байтов, прочитанных до возникновения ошибки |
UnmarshalTypeError | Offset | int64 | Число байтов, прочитанных до возникновения ошибки |
UnmarshalTypeError | Struct | string | Имя корневого типа, содержащего проблемное поле |
UnmarshalTypeError | Field | string | Полный путь от корневого узла до проблемного значения |
UnsupportedValueError | Str | string | Текстовое представление неподдерживаемого значения (например, NaN, +Inf) |
Когда Struct / Field у UnmarshalTypeError непусты, Error() выводит json: cannot unmarshal <value> into Go struct field <Struct>.<Field> of type <type> — дословно как в стандартной библиотеке.
Необязательный параметр cfg
Все дополнительные параметры cfg ...Config являются необязательными (variadic). Без них поведение на обычных данных совпадает со стандартной библиотекой (граничные различия стандартной проверки ввода — см. Различия в поведении ниже); передавайте их, только когда нужно включить режим безопасности, кэш и другие расширенные возможности.
Три намеренных исключения для cfg (из проектных соглашений библиотеки):
- Вариадический параметр типизированных функций чтения (
GetTyped,GetString,GetIntи др.) — это значение по умолчанию, а не cfg — Go допускает только один вариадический параметр. Для типизированного чтения с конфигурацией используйтеSafeGetили типизированные методы чтения на Processor, созданном черезNew(cfg)(например,GetString,GetInt). - Удобные варианты (
SetCreate,SetMultipleCreate,DeleteClean) эквивалентны обычным версиям с принудительно включёнными флагамиCreatePaths(илиCleanupNulls+CompactArrays). Validвозвращает одиночныйbool(сигнатура стандартной библиотеки); когда нужна причина сбоя, используйтеValidWithConfig(возвращаетbool, error).
Пример кода: меняется только import
Пример ниже показывает результат замены «только import»: кодирование, декодирование и использование тегов структур (struct tag) полностью совпадают с encoding/json:
package main
import (
"fmt"
"github.com/cybergodev/json"
)
func main() {
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Tags []string `json:"tags"`
}
// Кодирование — в точности как в encoding/json
user := User{Name: "Alice", Age: 30, Tags: []string{"go", "json"}}
b, err := json.Marshal(user)
if err != nil {
panic(err)
}
fmt.Println(string(b))
// Вывод: {"name":"Alice","age":30,"tags":["go","json"]}
// Декодирование — в точности как в encoding/json
var u User
if err := json.Unmarshal(b, &u); err != nil {
panic(err)
}
fmt.Printf("%+v\n", u)
// Вывод: {Name:Alice Age:30 Tags:[go json]}
}Дополнительные возможности
После миграции, сохраняя совместимость со стандартной библиотекой, вы можете по мере необходимости использовать возможности, недоступные в stdlib:
| Возможность | Пример | Подробнее |
|---|---|---|
| Запросы по путям | json.GetString(data, "user.name") | Синтаксис выражений пути |
| Получение со значением по умолчанию | json.GetInt(data, "timeout", 30) | Функции запроса |
| Обобщённое получение | json.GetTyped[User](data, "user") | Обобщённые операции |
| Изменение по пути | json.Set(data, "user.name", "Bob") | Операции изменения |
| Проверка по схеме | json.ValidateSchema(data, schema) | Валидация Schema |
| Потоковый JSONL | json.StreamLinesInto[T](r, fn) | Обработка JSONL |
| Высокопроизводительный процессор | p, _ := json.New() | Введение в Processor |
| Предразбор/предкомпиляция путей | p.PreParse / p.CompilePath | Введение в Processor |
| Параллельная итерация | json.NewParallelIterator(items).ForEach(fn) | Параллельная обработка |
| Отмена по контексту | json.GetWithContext(ctx, data, path) | Функции запроса |
| Глубокое сравнение JSON | json.CompareJSON(a, b) | Вспомогательные инструменты |
| Хуки/аудит/замеры | p.AddHook(json.LoggingHook(logger)) | Система хуков Hook |
| Режим безопасности | json.SecurityConfig() | Режим безопасности |
| Статистика/проверка здоровья | json.GetStats() / json.GetHealthStatus() | Введение в Processor |
Различия в поведении
Для обычных данных поведение при конфигурации по умолчанию совпадает с encoding/json. Стоит помнить: cybergodev/json по умолчанию несёт слой проверки безопасности ввода (такова его позиция безопасной JSON-библиотеки) — ввод, выходящий за лимиты или содержащий опасные шаблоны, отклоняется, тогда как стандартная библиотека принимает всё. Различия сведены в таблицу:
| Различие | encoding/json | Поведение CyberGo по умолчанию | Если нужно другое поведение |
|---|---|---|---|
| Размер ввода | Без ограничений | Свыше 100MB (MaxJSONSize) возвращает ErrSizeLimit | Увеличить cfg.MaxJSONSize |
| Глубина вложенности | Без явного ограничения | Свыше 200 уровней возвращает ErrDepthLimit | Настроить MaxNestingDepthSecurity |
| Опасные шаблоны содержимого | Не проверяются | 28 встроенных шаблонов блокируются по умолчанию (__proto__, <script, javascript:, eval(, onload и др.), возвращается ErrSecurityViolation | После подтверждения доверия установить cfg.DisableDefaultPatterns = true (ключевые шаблоны вроде __proto__ всё равно блокируются) |
| Ширина контейнеров | Без ограничений | Один объект ≤ 100 000 ключей, один массив ≤ 100 000 элементов | Настроить MaxObjectKeys / MaxArrayElements |
| Некорректный UTF-8 | Заменяется на U+FFFD при декодировании | Немедленный отказ (ErrInvalidJSON) | Заранее исправить кодировку ввода |
| BOM-префикс | Синтаксическая ошибка | Отклоняется (ErrInvalidJSON) | Предобработать и убрать BOM |
Два пункта, которые часто трактуют неверно:
- Более информативные ошибки:
JsonsError, возвращаемый при сбое операций с путями, содержит имя операции, путь и первопричину (поддерживаетerrors.Is/errors.AsиUnwrap), но не меняет типы ошибок функций, совместимых со стандартной библиотекой (Unmarshal/Decodeи др.) — они по-прежнему возвращают стандартные формыSyntaxError,UnmarshalTypeErrorи т. п. - Проверка действует только на ввод: перечисленные ограничения касаются текстового ввода JSON (
Unmarshal,Get,Parse,Validи др.); при кодировании Go-значений черезMarshal/Encodeпроверка содержимого не выполняется.
При работе с недоверенным вводом рекомендуется сразу использовать пресет json.SecurityConfig() (более строгие лимиты + полное сканирование), см. Режим безопасности.
FAQ по миграции
Вопрос: изменилось ли поведение json.Number с большими числами?
Нет. Decoder.UseNumber() соответствует стандартной библиотеке; поведение Number.Int64()/Float64() не изменилось. Когда нужно сохранить исходный текст числа, используйте json.Number как обычно.
Вопрос: совпадает ли поведение HTML-экранирования по умолчанию?
Да. Marshal/Encode по умолчанию экранируют <, >, & (как и стандартная библиотека); Encoder.SetEscapeHTML(false) отключает это — поведение и сигнатура совместимы.
Вопрос: а если существующий код использует пользовательские типы с json.Marshaler/json.Unmarshaler?
Полная совместимость. Оба интерфейса работают как обычно; пользовательские типы, реализующие их, ведут себя одинаково при кодировании/декодировании.
Вопрос: можно ли использовать новые возможности только в новом коде, не трогая старый?
Да, это и есть проектная цель. Функции уровня пакета кэшируют соответствующий Processor по «хвостовому параметру cfg» (см. соглашения по cfg выше); вызовы без cfg идут через глобальный процессор с конфигурацией по умолчанию — на обычных данных он совпадает со стандартной библиотекой, различия стандартной проверки ввода см. в таблице Различия в поведении выше.
Вопрос: Unmarshal отклоняет корректные данные со словами onload, eval( и т.п. — что делать?
Это стандартная проверка ввода блокирует шаблоны инъекций. После подтверждения доверия к вводу набор шаблонов по умолчанию можно отключить:
cfg := json.DefaultConfig()
cfg.DisableDefaultPatterns = true
err := json.Unmarshal(data, &v, cfg)Обратите внимание: три ключевых шаблона __proto__, constructor[, prototype. блокируются всегда и не зависят от этого переключателя. Если нужно только дополнить правила, добавьте пользовательские шаблоны через AdditionalDangerousPatterns, не отключая набор по умолчанию.
Вопрос: документ больше 100MB отклоняется с ErrSizeLimit — как обработать?
Два пути: если действительно нужна обработка целиком — увеличьте cfg.MaxJSONSize; предпочтительнее перейти на потоковую обработку (NewStreamIterator / NewStreamObjectIterator для поэлементного чтения или семейство JSONL для построчной), избегая загрузки единым блоком в память, см. Обработка больших файлов.
Что дальше
- Быстрый старт — основные возможности за 5 минут
- Синтаксис выражений пути — синтаксис запросов по путям
- Шпаргалка — быстрый справочник по API