I'm trying to marshal a struct into json (works as expected) and directly unmarshalling it again, but it seems as if information gets lost.
This is probably a design flaw in my application but as I'm a go beginner I don't know better. Help appreciated.
package main
import (
"encoding/json"
"fmt"
)
type Flow interface {
Exec(input map[string]string) (output map[string]string, err error)
}
type FlowData struct {
Static map[string]string
Output map[string]string
}
type FooFlow struct {
Data FlowData
}
func (flow FooFlow) Exec(input map[string]string) (output map[string]string, err error) {
output = map[string]string{"message": flow.Data.Static["message"]}
return output, nil
}
type BarFlow struct {
Data FlowData
}
func (flow BarFlow) Exec(input map[string]string) (output map[string]string, err error) {
output = map[string]string{"message": flow.Data.Static["prefix"] + "_bar"}
return output, nil
}
type Pipeline struct {
Entrypoint string
Flows map[string]Flow
}
func main() {
foo := FooFlow{
Data: FlowData{
Static: map[string]string{"message": "foo"},
},
}
bar := BarFlow{
Data: FlowData{
Static: map[string]string{"prefix:": "baz"},
},
}
pipe := Pipeline{
Entrypoint: "foobar",
Flows: map[string]Flow{
"foo": foo,
"bar": bar,
},
}
data, _ := json.Marshal(pipe)
fmt.Printf("pipe1: %+v
", pipe)
fmt.Println("json:", string(data))
var pipe2 Pipeline
json.Unmarshal(data, &pipe2)
fmt.Printf("pipe2: %+v
", pipe2)
}
Executing this gives the following result:
pipe1: {Entrypoint:foobar Flows:map[foo:{Data:{Static:map[message:foo] Output:map[]}} bar:{Data:{Static:map[prefix::baz] Output:map[]}}]}
json: {"Entrypoint":"foobar","Flows":{"bar":{"Data":{"Static":{"prefix:":"baz"},"Output":null}},"foo":{"Data":{"Static":{"message":"foo"},"Output":null}}}}
pipe2: {Entrypoint:foobar Flows:map[bar:<nil> foo:<nil>]}
Apparently all information gets correctly marshalled into json. But the unmarshalling ignores the actual values of the Flows as just adds them to the map as <nil>
.
How to properly solve this?
When a struct field is of an interface type, encoding/json
has no way to know what concrete type to use to unmarshal into it, so it skips it. Either use a concrete type in the definition, or prepopulate the interface field(s) with empty concrete instances that it can unmarshal into.