Unmarshal embedded field pointer panics when field implements UnmarshalJSON - go

I have a struct that embeds an embedded pointer to another struct. When I use the default json.Unmarshal behavior, it works perfectly. But when I implement UnmarshalJSON for the embedded struct's type but not the outer struct, then go panics with null pointer dereference.
If I implement UnmarshalJSON for the outer struct type as well, then it works. However, the outer struct has many fields that I would rather not have to manually unmarshal.
Why does implementing UnmarshalJSON on one and not the other cause a panic?
Is there a way to get it work without implemented UnmarshalJSON for the outer type?
If not, is there a simpler/less manual way to implement UnmarshalJSON for the outer type?
Note: There is a question with a similar title, "json.Unmarshal fails when embedded type has UnmarshalJSON
", but the issue there is different from mine.
tl;dr: The rest of this question is just a lengthy example of the above.
Base Example
(play.golang.org version of example)
The two structs, one with an embedded field pointer to the other:
(Simplified for example -- this doesn't really need its own UnmarshalJSON but it demonstrates the problem.)
type Obj struct {
X int `json:"x"`
}
type Container struct {
*Obj
Y int `json:"y"`
}
Invoking unmarshal:
func main() {
b := []byte(`{"x": 5, "y": 3}`)
c := &Container{}
err := json.Unmarshal(b, c)
if err != nil {
fmt.Printf("error ummarshalling json: %+v\n", err)
return
}
fmt.Printf("unmarshalled: %+v --> %+v\n", c, c.Obj)
}
Without implementing any UnmarshalJSON funcs, this works fine:
unmarshalled: &{Obj:0x416080 Y:3} --> &{X:5}
Panic
But, if I add UnmarshalJSON to the embedded Obj type only, then the program panics, as the json.Unmarshal call passes a nil pointer when it tries to unmarshal *Obj.
func (o *Obj) UnmarshalJSON(b []byte) (err error) {
m := make(map[string]int)
err = json.Unmarshal(b, &m)
if err != nil {
return nil
}
o.X = m["x"] // the line indicated by panic
return nil
}
Output:
panic: runtime error: invalid memory address or nil pointer dereference
[...]
main.(*Obj).UnmarshalJSON(0x0, 0x416030, 0x10, 0x10, 0x0, 0x0)
/tmp/sandbox185809294/main.go:18 +0x130
[...]
Question: Why does it panic here but not with the default unmarshal behavior? I'd think that if a nil *Obj is being passed here, then the default behavior also passes around a nil pointer...
Fixing the panic
It no longer panics when I implement UnmarshalJSON for the outer Container type:
func (c *Container) UnmarshalJSON(b []byte) (err error) {
m := make(map[string]int)
err = json.Unmarshal(b, &m)
if err != nil {
return err
}
c.Obj = &Obj{X: m["x"]}
c.Y = m["y"]
return nil
}
But unmarshalling Container manually this way gets tedious if both the real Container and real Obj have more fields than this, each with different types.
Question: Is there a simpler way to prevent this panic?

Because the default behavior checks for nil and your custom unmarshaller does not. You need some logic in your UnmarshalJSON to check if o is nil and behave appropriately, instead of assuming o is not nil (by trying to access one of its fields), thereby triggering a panic.
func (o *Obj) UnmarshalJSON(b []byte) (err error) {
if o == nil {
return nil // maybe? What do you want to happen in this case?
}
m := make(map[string]int)
err = json.Unmarshal(b, &m)
if err != nil {
return nil
}
o.X = m["x"] // the line indicated by panic
return nil
}
Also just for future reference, your *Obj field is not an "anonymous field", it is an embedded field: https://golang.org/ref/spec#Struct_types

Related

Assign empty slice without referring to its type?

My code calls a library function which looks roughly like this:
func Search() ([]myLibrary.SomeObject, error) {
var results []apiv17.SomeObject
// ...
if (resultsFound) {
results = append(results, someResult)
}
return results
}
...and my code calls it and then marshals it to JSON.
results, err := myLibrary.Search()
bytes, err := json.Marshal(results)
Now the problem is that because of the way the Search function is written (and let's assume we can't change it), it'll return an uninitialized nil slice if there are no results. And unfortunately, there is no way to configure encoding/json to encode nil slices as [] (see e.g. this proposal with ongoing discussion).
Explicitly checking for nil solves the problem:
results, err := myLibrary.Search()
if results == nil {
results = []apiv17.SomeObject{}
}
bytes, err := json.Marshal(results)
...but it also adds an explicit dependency on the return type, apiv17.SomeObject. That's inconvenient because that type frequently changes in the library. E.g. in the next library version it might be apiv18.SomeObject.
With the nil check above, I'll have to update my code every time that happens.
Is there any way to avoid this and assign an empty, non-nil slice to the variable without explicitly referring to its type? Something like this:
results = [](type of results){}
Go 1.18
You can use a generic function that captures the slice's base type and returns a slice of length zero:
func echo[T any](v []T) []T {
return make([]T, 0)
}
func main() {
n := foo.GetFooBar()
if n == nil {
n = echo(n) // no need to refer to apiv17 here
}
bytes, _ := json.Marshal(n)
fmt.Println(string(bytes)) // prints []
}
The purpose of requiring a regular argument v []T in echo is to allow type inference to unify the slice []apiv17.SomeObject with the argument []T and infer T as the base type apiv17.SomeObject, so that you can call it just as echo(n) and no explicit type parameter.
The package apiv17 is of course known at compile time because it's transitively imported via myPackage, so you can take advantage of this and type inference to avoid adding an explicit import statement for apiv17.
This is how it looks like on the multi-file playground: https://go.dev/play/p/4ycTkaGLFpo
The type is declared in bar package, but main only imports play.ground/foo and only uses foo.GetFooBar.
Go 1.17 and below
Reflection. Just change the echo function from above to taking an interface{} argument (there's no any in Go 1.17, remember?) and do the deed with reflect.MakeSlice:
func set(v interface{}) {
rv := reflect.ValueOf(v)
if rv.Kind() != reflect.Ptr {
panic("not a ptr")
}
reflect.Indirect(rv).Set(reflect.MakeSlice(rv.Type().Elem(), 0, 0))
}
Then pass a pointer to the slice, so that you can set its value with reflection.
func main() {
n := foo.GetFooBar()
if n == nil {
set(&n)
}
fmt.Printf("type: %T, val: %v, is nil: %t\n", n, n, n == nil)
// type: []bar.FooBar, val: [], is nil: false
bytes, _ := json.Marshal(n)
fmt.Println(string(bytes)) // prints [] again
}
Go 1.17 playground: https://go.dev/play/p/4jMkr22LMF7?v=goprev
The other answer describes how to create an empty slice.
But you can solve your original issue much simpler: if results is nil, you don't need to create a empty slice, regardless of whatever element type it would have, the JSON marshaling would be [] anyway. So if results is nil, no need to call json.Marshal(), just "output" []:
results, err := myLibrary.Search()
var bytes []byte
if results == nil {
bytes = []byte{'[', ']' } // JSON marshaling result is "[]"
} else {
bytes, err = json.Marshal(results)
// Handle error
}

How to get the underlying value of pointer type in Go?

I found this question How to get a pointer to the underlying value of an Interface{} in Go, but it looks too unsafe for me.
Of course I could use * to unpack it but I have to add nil check every time on caller side.
x := &some_type
fmt.Println(*x)
I am expecting the function that return default value of the base type if the pointer is nil.
x := Unpacker(some_type)
I'd just check for nil with an if statement. It's the reasonable thing to do. Though if you want to explore alternatives, read on.
In Go 1.18 you can accomplish this with a simple generic function:
func val[T any](v *T) T {
if v != nil {
return *v
}
return *new(T) // zero value of T
}
However this works only for pointer types in the form *T. There's other types in Go which have nil as zero value and are not pointers. Or this function could still return nil if you pass a pointer to such a type, like *[]int. Unfortunately there isn't a handy way to declare a constraint for all possible nillable types1.
With Go 1.17 and below you can use a type switch if the set of possible types is known, but then have to assert the result. This has the minor advantage of permitting ad-hoc initialization of nillable types:
func val(v interface{}) interface{} {
switch t := v.(type) {
case *string:
if t != nil {
return *t
}
return ""
case *[]string:
if t != nil {
return *t
}
return []string{}
default:
panic("unexpected type")
}
}
Or just use reflection, with the same limitations of having to assert the return, or risking to return nil again:
func val(v interface{}) interface{} {
t := reflect.TypeOf(v)
if t == nil || t.Kind() != reflect.Ptr {
panic("invalid input")
}
rv := reflect.ValueOf(v)
if rv.IsNil() {
return reflect.Zero(rv.Type().Elem()).Interface()
}
return v
}
Playground: https://go.dev/play/p/9dk0hWay90j
1: mainly because such a constraint would have to capture the key and/or value types of the map type, and decide what to (arbitrarily) return in those cases.
I am accepting another answer, but here is what I tried which apparently work for primitives too.
func Unwrap[T any](x *T) (r T) {
if x != nil {
r = *x
}
return
}

How to correctly check io.Reader for nil?

If you create a variable of type bytes.Buffer (without initialization) and assign it to a field of type io.Reader, then after checking io.Reader for nil there will be an error: invalid memory address or nil pointer dereference. How to check this correctly to avoid such errors?
Playground
package main
import (
"bytes"
"io"
"io/ioutil"
)
type Request struct {
Body io.Reader
}
func main() {
var data *bytes.Buffer
request := &Request{
Body: data,
}
if request.Body != nil {
ioutil.ReadAll(request.Body) // panic: runtime error: invalid memory address or nil pointer dereference
}
}
To check if an io.Reader (or any other interface) value is nil, you simply compare it to nil.
Whether a non-nil io.Reader is a meaningful implementation, that's another question.
E.g. is this implementation meaningful?
type panicReader struct{}
func (panicReader) Read(p []byte) (int, error) {
panic("foo")
}
panicReader certainly implements io.Reader, but whenever you call its Read() method, it will always panic.
There is bytes.Buffer. A pointer to it implements io.Reader. But calling Buffer.Read() on a nil *bytes.Buffer pointer value will panic. But not because you can't call methods on nil pointer receivers, but because the implementation of bytes.Buffer.Read() tries to dereference the pointer receiver, and this dereference operation is what causes the panic:
// Excerpt from bytes.Buffer.Read implementation
func (b *Buffer) Read(p []byte) (n int, err error) {
b.lastRead = opInvalid
if b.empty() {
// ...
}
You can't make a general conclusion here (just yet). See this io.Reader implementation:
type myBuffer struct{}
var count int
func (*myBuffer) Read(p []byte) (int, error) {
if len(p) > 0 {
count++
if count >= 10 {
return 0, io.EOF
}
p[0] = 'a'
return 1, nil
}
return 0, nil
}
*myBuffer implements io.Reader, and its Read() method does not use the pointer receiver value. What does this mean? You can call Read() on a nil *myBuffer value:
var data *myBuffer
request := &Request{
Body: data,
}
if request.Body != nil {
data, err := ioutil.ReadAll(request.Body)
fmt.Println(string(data), err)
}
This will output (try it on the Go Playground):
aaaaaaaaa <nil>
So the conclusion is this: usually types that have methods with pointer receiver require a non-nil pointer because they use the pointed object (in case of bytes.Buffer they use the fields of the pointed struct). To use such types (to have a meaningful implementation of implemented interfaces), you often need a non-nil pointer value for the methods to "work". This–however–is not always a requirement as the above myBuffer implementation shows. It's your job to always read the documentation of the used types and methods to avoid such misuses (e.g. trying to use a nil *bytes.Buffer).
See related question:
Hiding nil values, understanding why Go fails here
Go reflection with interface embedded in struct - how to detect "real" functions?

Cast interface to concrete type - type switch

I am looking for a way to cast an interface into the concrete type to save a lot of source code.
The initial situation are two functions of a webserver handler. They differ only in that one function decodes an array of structs and the other decodes a single struct and stores it in the database. The functions which have to be called for saving are identical depending on the type.
To decide whether an array or a struct is passed, it is tried to cast the interface into the type and then to pass this appropriately as a parameter of the function. Similar as it is described in the documentation and in the stackoverflow post.
However, I do not get the concrete type as expected and the program always runs into the default section. What am I doing wrong or have I not taken into account?
These are the outputs of the default section:
# interface is a struct
... or a single repository struct: map[string]interface{}
# interface is an array of structs
... or a single repository struct: []interface{}
Below is the source code with the functions
func (rh *RouteHandler) AddOrUpdateRepository(rw http.ResponseWriter, req *http.Request) {
repository := new(types.Repository)
rh.addOrUpdateRepositories(rw, req, repository)
}
func (rh *RouteHandler) AddOrUpdateRepositories(rw http.ResponseWriter, req *http.Request) {
repositories := make([]*types.Repository, 0)
rh.addOrUpdateRepositories(rw, req, repositories)
}
func (rh *RouteHandler) addOrUpdateRepositories(rw http.ResponseWriter, req *http.Request, v interface{}) {
defer req.Body.Close()
switch req.Header.Get("Content-Type") {
case "application/xml":
xmlDecoder := xml.NewDecoder(req.Body)
err := xmlDecoder.Decode(&v)
if err != nil {
rw.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(rw, "Failed to decode repositories or repository")
rh.ulogger.Error("Failed to decode repositories or repository: %v", err)
return
}
case "application/json":
fallthrough
default:
jsonDecoder := json.NewDecoder(req.Body)
err := jsonDecoder.Decode(&v)
if err != nil {
rw.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(rw, "Failed to decode repositories or repository")
rh.ulogger.Error("Failed to decode repositories or repository: %v", err)
return
}
}
var err error
switch x := v.(type) {
case map[string]*types.Repository:
for _, repository := range x {
err = rh.manager.AddOrUpdateRepository(context.Background(), repository)
}
case *types.Repository:
err = rh.manager.AddOrUpdateRepository(context.Background(), x)
case map[string][]*types.Repository:
for i := range x {
for j := range x[i] {
err = rh.manager.AddOrUpdateRepository(context.Background(), x[i][j])
}
}
case []*types.Repository:
err = rh.manager.AddOrUpdateRepository(context.Background(), x...)
case nil:
rw.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(rw, "Failed to cast interface")
rh.ulogger.Error("Failed to cast interface. Interface is a type of nil")
return
default:
rw.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(rw, "Failed to cast interface")
rh.ulogger.Error("Failed to cast interface. Interface does not match onto an array of repositories or a single repository struct: %T", x)
return
}
if err != nil {
rw.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(rw, "Failed to add repositories or repository")
rh.ulogger.Error("Failed to add repositories or repository: %v", err)
return
}
rw.WriteHeader(http.StatusCreated)
}
(Simplified a bit.)
You have a function with the following signature:
func addOrUpdateRepositories(v interface{})
and then you call it like this:
repository := new(types.Repository)
addOrUpdateRepositories(repository)
and like this:
repositories := make([]*types.Repository, 0)
addOrUpdateRepositories(repositories)
In the first call, the concrete type of the value stored in v will be *types.Repository (as new returns a pointer to the allocated value) and in the second call the concrete type of the value stored in v will be []*types.Repository—because that's what make was told to create.
Now you do a type-switch on v, which reads:
switch x := v.(type) {
case map[string]*types.Repository:
case map[string][]*types.Repository:
case nil:
default:
}
Leaving aside the case that if you do not call addOrUpdateRepositories passing it a nil v which cannot happen in the snippet from your question, the switch will always pick the default branch because the type of the concrete value stored in v is never map[string]*types.Repository or map[string][]*types.Repository.
I am not sure why you fail to see this, so probably you should refine your question or may be try to clear up your confusion in a comment to my answer?
Another shot in the dark: type conversions (note that Go does not have type casts, as #Flimzy pointed out) and type switches in Go do not actually change the underlying representation of the value they operate on—except for the limited set of ("everyone expects this") cases such as type-converting a float64 to int64, which are precisely documented.
So you cannot take a []*types.Repository (a slice of pointers to values of type types.Repository) and somehow force it "to become" map[string][]*types.Repository: that'd be a nonsensical thing to do for a number of reasons, with the most glaring being this: if you were writing the Go compiler, how would you carry out such a "type cast"? Suppose you were to really allocate a map, but then which key in that map should have been assigned the original (source) slice? What about type-converting a []*types.Repository to struct {foo []*types.Repository; bar []*types.Repository}?

Golang address operators and (*int)(Type) syntax

Starting to play around with golang and was looking at a custom json.Unmarshal. In a blog post the had the following:
type FlexInt int
func (fi *FlexInt) UnmarshalJSON(data []byte) error {
if data[0] != '"' {
return json.Unmarshal(data, (*int)(fi))
}
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
i, err := strconv.Atoi(s)
if err != nil {
return err
}
*fi = FlexInt(i)
return nil
}
And I understand what it is doing - but I dont understand (*int)(fi) part. Looking at the value of the fi pointer it is the same as (*int)(fi) - (*int)(fi) == fi. Yet when I change that line to simply fi it then does an infinite loop
The expression converts fi to an *int. The result contains the same address, but has a different type.
If a *FlexInt is passed to json.Unmarshal, then json.Unmarshal will call the *FlexInt.UnmarshalJSON method which calls json.Unmarshal and so on.
It's the same pointer, but with a different type. When json.Unmarshal is called with an interface{} that contains a FlexInt*, it calls FlexInt's UnmarshalJSON method. When it's called with an interface{} that contains an int*, it uses the builtin behavior. Since FlexInt and int have the same underlying type, it's acceptable to convert a pointer to one into a pointer to the other, but it's the "actual" type that the interface will be marked with.

Resources