从Java到Golang:解组多态JSON

时间:2019-11-28 00:29:23

标签: json go

此处是新手golang程序员。我正在用go重写Java应用程序。 Java应用程序使用一个对象模型,该对象模型利用Jackson的Polymorphic Typing功能来处理与JSON的编组/解组。假设我无法更改JSON对象的形状。

鉴于go提供的多态性是接口{},因此提出一个“对象模型”以提供与多态性相同的使用模式一直是一项挑战。

我第一次尝试解决问题是这样的:


type Thing struct {
    ID   string `json:"id"`
    Type string `json:"@type"`
}

type SpecificThing struct {
    Thing
    SpecificField string `json:"specificField"`
}

type AnotherSpecificThing struct {
    Thing
    AnotherSpecificField string `json:"anotherSpecificField"`
}

但这需要将具体的子类型实例传递给unmarshal方法。

我试图通过创建“联盟结构”作为元帅和元帅的工具来解决此问题:

type Thing struct {
    ID      string      `json:"id"`
    Type    string      `json:"@type"`
    Payload interface{} `json:"-"`
}

type SpecificThing struct {
    SpecificField string `json:"specificField"`
}

type AnotherSpecificThing struct {
    AnotherSpecificField string `json:"anotherSpecificField"`
}

type superThing struct {
    ID   string `json:"id"`
    Type string `json:"@type"`
    *SpecificThing
    *AnotherSpecificThing
}

func (t *Thing) UnmarshalJSON(b []byte) error {
    //error checking omitted for brevity
    var st superThing

    _ = json.Unmarshal(b, &st)

    t.ID = st.ID
    t.Type = st.Type

    switch t.Type {
    case "specificThing":
        t.Payload = st.SpecificThing
    case "anotherSpecificThing":
        t.Payload = st.AnotherSpecificThing
    }
    return nil
}

func TestUnmarshal(t *testing.T) {
    data := []byte(`
    {
        "id":"some id",
        "@type":"specificThing",
        "specificField": "some specific field value"
    }   
    `)

    var th Thing
    _ = json.Unmarshal(data, &th)
}

就此动态JSON而言,只要能够进行封送和解组,就可以很好地工作。不利的一面是,模型的使用者需要在有效载荷上进行类型声明,以与子类型进行交互以进行任何实际工作。理想情况下,是否存在一种解决方案可以绕过“事物”抽象层次,并且还可以在需要时与子类型进行交互?基于阅读,接口可以用于这种情况,但是我正在努力查看该模型如何利用它们。有想法吗?

1 个答案:

答案 0 :(得分:0)

我认为使Thing成为接口并实现UnmarshalJSON可以为您提供所需的东西(如果用户需要接口不提供的功能,则用户仍然必须使用类型断言/切换,但这是不可避免的)。看起来类似于以下内容:

()=><p>hello world!</p>

Greg TrowBridge's blog中详细介绍了此方法。

  • 在OP指出我错过了一个测试用例后进行了更新。代码现已通过测试,可以正常运行。