azertiti
azertiti

Reputation: 3150

JSON marshalling with type not exported

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

Answers (2)

user29743183
user29743183

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

poy
poy

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

Related Questions