Интерфейс json.Unmarshaler
Интерфейс json.Unmarshaler находится в пакете encoding/json
и позволяет реализовать кастомную логику десериализации JSON-данных
в пользовательский тип. Интерфейс содержит единственный метод
UnmarshalJSON, который принимает срез байт (JSON-данные)
и возвращает ошибку. Если ваш тип реализует этот интерфейс,
то при вызове json.Unmarshal будет использоваться ваша
реализация метода вместо стандартной.
Синтаксис
type Unmarshaler interface {
UnmarshalJSON([]byte) error
}
Для реализации интерфейса необходимо определить метод
UnmarshalJSON с указанным синтаксисом. Метод получает
исходные JSON-данные в виде байтового среза и должен заполнить
поля структуры, используя собственную логику разбора.
Пример
Давайте реализуем кастомную десериализацию для структуры, которая хранит дату в строковом формате:
package main
import (
"encoding/json"
"fmt"
"strings"
)
type Person struct {
Name string
Age int
City string
}
func (p *Person) UnmarshalJSON(data []byte) error {
var raw map[string]interface{}
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
if name, ok := raw["name"].(string); ok {
p.Name = strings.ToUpper(name)
}
if age, ok := raw["age"].(float64); ok {
p.Age = int(age)
}
if city, ok := raw["city"].(string); ok {
p.City = strings.ToUpper(city)
}
return nil
}
func main() {
jsonData := []byte(`{"name":"alex","age":25,"city":"moscow"}`)
var p Person
err := json.Unmarshal(jsonData, &p)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Name: %s, Age: %d, City: %s\n", p.Name, p.Age, p.City)
}
Результат выполнения кода:
"Name: ALEX, Age: 25, City: MOSCOW"
В этом примере метод UnmarshalJSON преобразует
все строковые поля структуры в верхний регистр в процессе
десериализации. Обратите внимание, что метод должен быть
определен на указателе на структуру.
Пример
Рассмотрим пример с обработкой нестандартного формата данных, где необходимо преобразовать строку в числовой тип:
package main
import (
"encoding/json"
"fmt"
"strconv"
)
type Product struct {
ID string
Price int
}
func (p *Product) UnmarshalJSON(data []byte) error {
var raw map[string]interface{}
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
if id, ok := raw["id"].(string); ok {
p.ID = id
}
if priceStr, ok := raw["price"].(string); ok {
price, err := strconv.Atoi(priceStr)
if err != nil {
return err
}
p.Price = price
}
return nil
}
func main() {
jsonData := []byte(`{"id":"p001","price":"1500"}`)
var product Product
err := json.Unmarshal(jsonData, &product)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("ID: %s, Price: %d\n", product.ID, product.Price)
}
Результат выполнения кода:
"ID: p001, Price: 1500"
В этом примере мы десериализуем JSON, где поле price
передается как строка, но структура ожидает числовой тип.
Метод UnmarshalJSON выполняет преобразование с помощью
функции strconv.Atoi.
Пример
Рассмотрим обработку ошибок при десериализации с использованием
интерфейса json.Unmarshaler:
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Username string
Email string
}
func (u *User) UnmarshalJSON(data []byte) error {
var raw map[string]interface{}
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
username, ok := raw["username"].(string)
if !ok || username == "" {
return fmt.Errorf("username is required")
}
u.Username = username
email, ok := raw["email"].(string)
if !ok || email == "" {
return fmt.Errorf("email is required")
}
u.Email = email
return nil
}
func main() {
jsonData := []byte(`{"username":"john","email":"john@example.com"}`)
var user User
err := json.Unmarshal(jsonData, &user)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Username: %s, Email: %s\n", user.Username, user.Email)
}
Результат выполнения кода:
"Username: john, Email: john@example.com"
В этом примере метод UnmarshalJSON проверяет наличие
обязательных полей и возвращает ошибку, если данные некорректны.
Это позволяет выполнять валидацию данных непосредственно
в процессе десериализации.
Смотрите также
-
интерфейс
json.Marshaler,
который позволяет реализовать кастомную сериализацию -
функцию
json.Unmarshal,
которая выполняет десериализацию JSON-данных -
функцию
json.Marshal,
которая выполняет сериализацию данных в JSON -
функцию
json.Valid,
которая проверяет корректность JSON-данных