Reputation: 3150
I'm want to use a custom type which is not exported and define an interface to use it. The custom type will implement the interface and everything works fine except for unmarshaling from JSON.
I created an example to explain it better:
type (
Value interface {
Set(k, v string)
}
value map[string]string
)
func New() Value {
return value{}
}
func (val value) Set(k, v string) {
val[k] = v
}
This approach will not provide direct access to the map and force the usage of New() function to create objects of type "Value".
When trying to unmarshal in an object created with New() I'm getting the error:
Failed to unmarshal value json: cannot unmarshal object into Go value of type main.Value
That can be fixed by making New() return "value" instead of "Value" but will still be a problem when trying to unmarshal an object like:
Storage struct {
Val Value `json:"val"`
}
Any suggestions? Implementing Unmarshaler doesn't help in this case. I create a go snippet with this example: https://play.golang.org/p/IEalgBCsTVR
Upvotes: 2
Views: 11140
Reputation:
you need to swap the pointers - the interface can be passed by value, but the underlying value needs to be passed by reference:
package main
import (
"encoding/json"
"fmt"
)
type world map[string]string
func (w world) UnmarshalJSON(data []byte) error {
w1 := map[string]string(w)
return json.Unmarshal(data, &w1)
}
func main() {
var hello json.Unmarshaler = &world{} // REFERENCE
err := json.Unmarshal([]byte(`{"a": "b"}`), hello) // VALUE
if err != nil {
panic(err)
}
fmt.Println(hello) // &map[a:b]
}
Upvotes: -1
Reputation: 10537
You need to give json.Unmarshal()
a pointer to a concrete type. So change (from your linked playground):
unm := New()
to
unm := New().(value)
Upvotes: 1