JSON Unmarshal不规则JSON字段

时间:2017-08-24 20:22:14

标签: json go

我有这段代码:

type Response struct {
    ID string `json:"id"`
    Tags Tags `json:"tags,omitempty"`
}

type Tags struct {
    Geo     []string `json:"geo,omitempty"`
    Keyword []string `json:"keyword,omitempty"`
    Storm   []string `json:"storm,omitempty"`
}

func (t *Tags) UnmarshalJSON(b []byte) (err error) {
    str := string(b)
    if str == "" {
        t = &Tags{}
        return nil
    }

    err = json.Unmarshal(b, t)
    if err != nil {
        return err
    }

    return nil
}

现在,我的JSON响应如下所示:

[{
    "id": "/cms/v4/assets/en_US",
    "doc": [{
            "id": "af02b41d-c2c5-48ec-9dbc-ceed693bdbac",
            "tags": {
                "geo": [
                    "DMA:US.740:US"
                ]
            }
        },
        {
            "id": "6a90d9ed-7978-4c18-8e36-c01cf4260492",
            "tags": ""
        },
        {
            "id": "32cfd045-98ac-408c-b464-c74e02466339",
            "tags": {
                "storm": [
                    "HARVEY - AL092017"
                ],
                "keyword": [
                    "hurrcane",
                    "wunderground"
                ]
            }
        }
    ]
}]

最好是我改变JSON响应才能正确完成,但我不能。 Unmarshaling继续出错(goroutine stack exceeds 1000000000-byte limit)。我最好使用easyjsonffjson进行此操作,但我们怀疑是否有可能。建议?

1 个答案:

答案 0 :(得分:0)

您的UnmarshalJSON函数以递归方式调用自身,这会导致堆栈的大小爆炸。

func (t *Tags) UnmarshalJSON(b []byte) (err error) {
    str := string(b)
    if str == "" {
        t = &Tags{}
        return nil
    }

    err = json.Unmarshal(b, t) <--- here it calls itself again
    if err != nil {
        return err
    }

    return nil
}

如果您有理由在json.Unmarshal函数内调用UnmarshalJSON,则必须使用其他类型。执行此操作的常用方法是使用本地别名:

    type tagsAlias Tags
    var ta = &tagsAlias
    err = json.Unmarshal(b, ta)
    if err != nil {
        return err
    }

    *t = Tags(ta)

另请注意,t = &Tags{}在您的功能中不执行任何操作;它为t分配一个新值,但是一旦函数退出,该值就会丢失。如果您确实要分配到t,则需要*t;但你根本不需要它,除非你试图取消设置先前设置的*Tags实例。