2016-04-07 6 views
0

Gibt es eine Möglichkeit, benutzerdefinierte Strukturen beim Kodieren/Dekodieren mit Json zu serialisieren?Golang benutzerdefinierte JSON-Serialisierung (tut etwas äquivalent zu gob.register() existieren für Json?)

sagen Sie 3 haben unterschiedliche individuelle structs (in meinem eigentlichen Code dort 10 sind), die über UDP gesendet werden, und Sie verwenden json zur Codierung:

type a struct { 
    Id int 
    Data msgInfo 
} 

type b struct { 
    Id  int 
    Data  msgInfo 
    Other metaInfo 
} 

type c struct { 
    Other metaInfo 
} 

Am recieving Ende Sie wissen wollen, ob Die empfangene Struktur war vom Typ a, b oder c, so dass sie beispielsweise an einen typspezifischen Kanal übergeben werden kann.

type msgtype reflect.Type 

. 
. 

nrOfBytes, err := udpConn.Read(recievedBytes) 
if err != nil {...} 

var msg interface{} 
err = json.Unmarshal(recievedBytes[0:nrOfBytes], &msg) 
if err != nil {...} 

u := reflect.ValueOf(msg) 
msgType := u.Type() 
fmt.Printf("msg is of type: %s\n", msgType) 

Mit gob dies leicht durch die Registrierung der Arten geschehen ist, aber ich habe json verwenden da es die Kommunikation über udp ist, so ist es trotzdem die benutzerdefinierten structs zu serialisiert? Ich möchte, dass die Druck

msg is of type: a 

sein, aber ich bin nur

msg is of type: map[string]interface {} 
+0

Wie Sie senden/eine Nachricht erhalten? Ich schlage vor, dass Sie einen Endpunkt mit einem Typ angeben, damit Sie bereits wissen, was Sie erwarten. Nehmen wir an, Sie haben eine REST API, dann sollte alles POST to/a zu einer Struktur geparst werden. – nvcnvn

+0

Ich habe versucht, was auch immer ich in einen Typ namens "Packet" packte, so dass ich nur diesen einen Typ mit einem "Data "Feld, das die benutzerdefinierte Struktur enthält. Leider hat sich nichts geändert –

Antwort

2

Eine Sache, die Sie tun können, ist die Verwendung des json.RawMessage Typs und eines benutzerdefinierten Wrappertyps. Dann, nach dem Empfang einer Nachricht, können Sie einen Schalter (oder verwenden Sie eine Karte von Konstruktoren), um die richtige Struktur zu bekommen.

Zum Beispiel (Weglassen Fehlerprüfung):

package main 

import ( 
    "encoding/json" 
    "fmt" 
)   

type Message struct { 
    Type string 
    Data json.RawMessage 
}   

func (m Message) Struct() interface{} { 
    unmarshaller, found := unmarshallers[m.Type] 
    if !found { 
     return nil 
    }  
    return unmarshaller([]byte(m.Data)) 
}   

type Foo struct { 
    ID int 
}   

var unmarshallers = map[string]func([]byte) interface{}{ 
    "foo": func(raw []byte) interface{} { 
     var f Foo 
     json.Unmarshal(raw, &f) 
     return f 
    },  
}   

func main() { 
    var body = []byte(`{"Type":"foo","Data":{"ID":1}}`) 
    var msg Message 
    json.Unmarshal(body, &msg) 

    switch s := msg.Struct().(type) { 
    case Foo: 
     fmt.Println(s) 
    }  
} 

Sehen Sie diesen Spielplatz Beispiel für eine Live-Demo http://play.golang.org/p/7FmQqnWPaE

+0

Vielen Dank, die Unmarsheller-Variable funktioniert super! –

0

Base auf Ihrem Kommentar bekommen, dies vielleicht eine Lösung:

type Packet { 
    Type string 
    Data []byte 
} 

Encode Funktion:

func packageEncode(i interface{}) ([]byte, error) { 
    b, err := json.Marshal(i) 
    if err != nil { 
    return nil, err 
    } 

    p := &Package{Data: b} 
    switch t.(type) { 
    case a: 
     p.Type = "a" 
    case b: 
     p.Type = "b" 
    case c: 
     p.Type = "c" 
    } 
    return json.Marshal(p) 
} 

Dann, wenn empfangene Nachricht und decode:

+0

Vielen Dank für Ihre Antwort :) –