亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

從 Java 到 Golang:解組多態 JSON

從 Java 到 Golang:解組多態 JSON

Go
四季花海 2023-08-07 15:03:49
新手 golang 程序員在這里。我正在用 go 重寫 java 應用程序。java 應用程序使用一個對象模型,該模型利用 Jackson 的多態類型功能來處理與 JSON 的編組/解組。假設我無法更改 JSON 對象的形狀。鑒于 go 提供的多態性是 interface{},因此就多態性而言,提出一個提供相同使用模式的“對象模型”一直是一個挑戰。我第一次嘗試解決這個問題看起來像這樣: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 方法。我試圖通過創建“Union Structs”作為編組和解組的工具來解決這個問題: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 回答

?
倚天杖

TA貢獻1828條經驗 獲得超3個贊

我認為使 Thing 成為一個接口并實現 UnmarshalJSON 這幾乎可以滿足您的需求(如果用戶需要接口未提供的功能,但這是不可避免的,他們仍然必須使用類型斷言/開關)。這看起來像下面這樣:


package main


import (

? ? "encoding/json"

? ? "fmt"

)


func main() {

? ? data := []byte(`

? ? {

? ? ? ? "id":"some id",

? ? ? ? "@type":"specificThing",

? ? ? ? "specificField": "some specific field value"

? ? }? ?

? ? `)


? ? var th ThingHolder?

? ? err := json.Unmarshal(data, &th)

? ? if err != nil {

? ? ? ? panic(err)

? ? }

? ? mySpecThing := th.T.(*SpecificThing )

? ? fmt.Printf("%v", mySpecThing)

}


type Thing interface {

? ? ID() string

}


type ThingHolder struct {

? ? T Thing

}


type SpecificThing struct {

? ? Id? ? ? ? ? ? string `json:"id"`

? ? Type? ? ? ? ? string `json:"@type"`

? ? SpecificField string `json:"specificField"`

}


func (s *SpecificThing) ID() string {

? ? return s.Id

}


func (t *ThingHolder) UnmarshalJSON(b []byte) error {

? ? var objMap map[string]*json.RawMessage

? ? err := json.Unmarshal(b, &objMap)

? ? if err != nil {

? ? ? ? return err

? ? }


? ? // Now lets see what 'things' the JSON contains

? ? // by looking at JSON keys

? ? jsonType, ok := objMap["@type"]

? ? if !ok {

? ? ? ? return fmt.Errorf("No Type")

? ? }

? ? var goType string

? ? err = json.Unmarshal(*jsonType, &goType)

? ? if err != nil {

? ? return fmt.Errorf("error getting type: %s", err)

? ? }? ?


? ? switch goType {

? ? case "specificThing":

? ? var st SpecificThing

? ? ? ? err = json.Unmarshal(b, &st)

? ? ? ? if err != nil {

? ? ? ? ? ? return err

? ? ? ? }

? ? ? ? t.T = &st

? ? default:

? ? return fmt.Errorf("Unknown type %s", goType )

? ? }


? ? return nil

}


在OP指出我錯過了一個測試用例后進行了更新。代碼現已測試且工作正常。


查看完整回答
反對 回復 2023-08-07
  • 1 回答
  • 0 關注
  • 155 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號