dongxing2030
2018-06-01 11:08
浏览 132

在Golang中处理JSON继承

I have a Java code that handles json inheritance the code is like this :

public class BaseMessage {
    private String messageId;
    private Integer type;
    ...
}

public class TextMessage  extends BaseMessage {
    private String recipient;
    private String sender;
    ...
}

public class SystemTextMessage  extends BaseMessage {
    private String field1;
    private String field2;
    ...
}

And some other classes

And I'm using Gson library like this:

    RuntimeTypeAdapterFactory<BaseMessage> runtimeTypeAdapterFactory = RuntimeTypeAdapterFactory
            .of(BaseMessage.class, "type")
            .registerSubtype(TextMessage.class,
                    String.valueOf(MessageType.TEXT_MESSAGE))
            .registerSubtype(SystemTextMessage.class,
                    String.valueOf(MessageType.SYSTEM_MESSAGE))
            ;

Gson gson = new GsonBuilder().registerTypeAdapterFactory(runtimeTypeAdapterFactory).create();
Type listType = new TypeToken<List<BaseMessage>>(){}.getType();
List<BaseMessage> list = gson.fromJson(json, listType);

And then I just iterate through the List and comparing by "instanceof".

And what about golang? Is there any way to do same thing? I failed to find something similar. Any 1 can help? Thank you.

  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

2条回答 默认 最新

  • duanbishai5271 2018-06-01 12:08
    已采纳

    Without using any external library, you could do:

    package main
    
    import (
        "encoding/json"
        "fmt"
        "reflect"
    )
    
    type BaseMessage struct {
        MessageId string `json:"messageId"`
        Type      int    `json:"type"`
    }
    
    type TextMessage struct {
        *BaseMessage
        Field1 string `json:"field1"`
        Field2 string `json:"field2"`
    }
    
    type SystemTextMessage struct {
        *BaseMessage
        Field1 string `json:"field1"`
        Field2 string `json:"field2"`
    }
    
    func parseJson(input []byte) []interface{} {
        var raw []map[string]interface{}
    
        json.Unmarshal(input, &raw)
        var elements []interface{}
        for _, element := range raw {
            typeId := int(element["type"].(float64))
    
            base := &BaseMessage{
                MessageId: element["messageId"].(string),
                Type:      typeId,
            }
            switch typeId {
            case 1:
                elements = append(elements, &TextMessage{base, element["field1"].(string), element["field2"].(string)})
                break
            case 2:
                elements = append(elements, &SystemTextMessage{base, element["field1"].(string), element["field2"].(string)})
                break
            }
        }
    
        return elements
    }
    
    func main() {
        input := []byte(`
                 [{
                   "messageId": "text",
                   "type": 1,
                   "field1": "field 1",
                   "field2": "field 2"
                 }, {
                   "messageId": "system",
                   "type": 2,
                   "field1": "field 1",
                   "field2": "field 2"
                 }]
            `)
    
        for _, element := range parseJson(input) {
            fmt.Println(reflect.TypeOf(element))
        }
    }
    

    You can give it a try here: https://play.golang.org/p/hB8qG6oflhR

    Be careful though, the code is not handling errors.

    I'm not sure if there's a more automatic way of doing it, but I believe you have to work with bare interface{} here.

    已采纳该答案
    打赏 评论
  • duanhai1455 2018-06-01 12:00

    In Go, you compose instead of inherit. Below, the Tesla struct embeds both Car and Computer by defining them as anonymous fields (i.e not giving them a name.)

    package main
    
    import (
        "fmt"
        "encoding/json"
    )
    
    type Car struct {
        Speed int
    }
    
    type Computer struct {
        Cores int
        Memory int
    }
    
    type Tesla struct {
        Car
        Computer
    }
    
    func main() {
        tesla := Tesla{
            Car{Speed: 200},
            Computer{Cores: 4, Memory: 4192},
        }
        b, _ := json.MarshalIndent(tesla, "", "\t")
        fmt.Println(string(b))
    }
    

    Outputs:

    {
        "Speed": 200,
        "Cores": 4,
        "Memory": 4192
    }
    

    Try it in the Go playground. This example encodes JSON, use json.Unmarshal to decode.

    打赏 评论

相关推荐 更多相似问题