插件窝 干货文章 Go语言JSON解析:重写UnmarshalJSON后字段丢失问题如何解决?

Go语言JSON解析:重写UnmarshalJSON后字段丢失问题如何解决?

字段 json UnmarshalJSON err 957    来源:    2025-03-15

在Go语言中,当你自定义了一个类型的 UnmarshalJSON 方法时,可能会导致某些字段在解析过程中丢失。这通常是因为你在自定义的 UnmarshalJSON 方法中没有正确处理所有的字段。以下是一些常见的原因和解决方法:

1. 未调用默认的 UnmarshalJSON 方法

如果你在自定义的 UnmarshalJSON 方法中没有调用默认的 UnmarshalJSON 方法,那么未处理的字段将会丢失。

解决方法:在自定义的 UnmarshalJSON 方法中,先解析你需要的字段,然后使用 json.Unmarshal 解析剩余的字段。

type MyStruct struct {
    Field1 string `json:"field1"`
    Field2 int    `json:"field2"`
    // 其他字段
}

func (m *MyStruct) UnmarshalJSON(data []byte) error {
    // 创建一个临时结构体来解析已知字段
    type Alias MyStruct
    aux := &struct {
        *Alias
    }{
        Alias: (*Alias)(m),
    }

    // 解析已知字段
    if err := json.Unmarshal(data, &aux); err != nil {
        return err
    }

    // 处理其他字段
    var raw map[string]json.RawMessage
    if err := json.Unmarshal(data, &raw); err != nil {
        return err
    }

    // 处理其他字段的逻辑
    // 例如:m.OtherField = raw["other_field"]

    return nil
}

2. 未正确处理 json.RawMessage

如果你在自定义的 UnmarshalJSON 方法中使用了 json.RawMessage,但没有正确处理它,可能会导致字段丢失。

解决方法:确保你正确处理了 json.RawMessage,并将其解析到相应的字段中。

func (m *MyStruct) UnmarshalJSON(data []byte) error {
    var raw map[string]json.RawMessage
    if err := json.Unmarshal(data, &raw); err != nil {
        return err
    }

    // 解析已知字段
    if err := json.Unmarshal(raw["field1"], &m.Field1); err != nil {
        return err
    }
    if err := json.Unmarshal(raw["field2"], &m.Field2); err != nil {
        return err
    }

    // 处理其他字段
    // 例如:if err := json.Unmarshal(raw["other_field"], &m.OtherField); err != nil { ... }

    return nil
}

3. 未正确处理嵌套结构体

如果你的结构体中有嵌套的结构体,并且你在自定义的 UnmarshalJSON 方法中没有正确处理它们,可能会导致字段丢失。

解决方法:确保你正确处理了嵌套的结构体,并递归调用 UnmarshalJSON 方法。

type NestedStruct struct {
    NestedField string `json:"nested_field"`
}

type MyStruct struct {
    Field1 string      `json:"field1"`
    Nested NestedStruct `json:"nested"`
}

func (m *MyStruct) UnmarshalJSON(data []byte) error {
    var raw map[string]json.RawMessage
    if err := json.Unmarshal(data, &raw); err != nil {
        return err
    }

    // 解析已知字段
    if err := json.Unmarshal(raw["field1"], &m.Field1); err != nil {
        return err
    }

    // 解析嵌套结构体
    if err := json.Unmarshal(raw["nested"], &m.Nested); err != nil {
        return err
    }

    return nil
}

4. 未正确处理 omitempty 标签

如果你的结构体字段使用了 omitempty 标签,并且在 JSON 数据中这些字段为空,那么这些字段将不会被解析。

解决方法:确保你在自定义的 UnmarshalJSON 方法中正确处理了 omitempty 标签。

type MyStruct struct {
    Field1 string `json:"field1,omitempty"`
    Field2 int    `json:"field2,omitempty"`
}

func (m *MyStruct) UnmarshalJSON(data []byte) error {
    var raw map[string]json.RawMessage
    if err := json.Unmarshal(data, &raw); err != nil {
        return err
    }

    // 解析已知字段
    if rawField1, ok := raw["field1"]; ok {
        if err := json.Unmarshal(rawField1, &m.Field1); err != nil {
            return err
        }
    }

    if rawField2, ok := raw["field2"]; ok {
        if err := json.Unmarshal(rawField2, &m.Field2); err != nil {
            return err
        }
    }

    return nil
}

总结

在自定义 UnmarshalJSON 方法时,确保你正确处理了所有字段,包括嵌套结构体和 omitempty 标签。通过使用 json.RawMessage 和临时结构体,你可以更灵活地控制 JSON 解析过程,避免字段丢失的问题。