I want byte slices that marshal and unmarshal in JSON using base64 RawURLEncoding
instead of StdEncoding
. There's no obvious way to do this through the encoding/json package, which is sensible, so I thought I'd create a subtype to do it.
type Thing []byte
Marshaling support is easy:
func (thing Thing) MarshalJSON() ([]byte, error) {
if thing == nil {
return []byte("null"), nil
}
return []byte(`"` + base64.RawURLEncoding.EncodeToString(thing) + `"`), nil
}
But Unmarshal not so much. I traced the encoding/json source, and came up with:
func (thing Thing) UnmarshalJSON(data []byte) error {
v := reflect.ValueOf(&thing)
if len(data) == 0 || data[0] == 'n' { // null
v.SetBytes([]byte{})
return nil
}
data = data[1 : len(data)-1]
dst := make([]byte, base64.RawURLEncoding.DecodedLen(len(data)))
n, err := base64.RawURLEncoding.Decode(dst, data)
if err != nil {
return err
}
v.SetBytes(Thing(dst[:n]))
return nil
}
But yields a panic in the call to SetBytes()
:
panic: reflect: reflect.Value.SetBytes using unaddressable value [recovered]
panic: reflect: reflect.Value.SetBytes using unaddressable value
I tried using a pointer to a slice, instead, which works (and doesn't require reflection), but causes other challenges elsewhere in my code that wants to work with slices instead of pointers.
So two questions, I guess:
- Is this the best way to go about getting byte slices to marshal using
RawURLEncoding
? - If so, how can I convince my byte slice subtype to reference the data decoded from the
RawURLEncoding
format?
Aucun commentaire:
Enregistrer un commentaire