0

I'm trying to figure out if there is a way to unmarshal JSON strings to a specific struct, using only the string and the intended type. Here is what I have come up with so far.

Code

package main

import (
    "encoding/json"
    "fmt"
    "reflect"
)

type Person struct {
    Name string `json:"name"`
}

func genericUnmarshal(jsonString string, t reflect.Type) interface{} {
    p := reflect.New(t)
    result := p.Interface()
    json.Unmarshal([]byte(jsonString), &result)
    return result
}

func main() {
    jsonData := "{\"name\":\"John\"}"
    unmarshalledPerson := genericUnmarshal(jsonData, reflect.TypeOf(Person{}))

    person := Person{Name: "John"}
    fmt.Printf("struct value: %+v type: %+v\n", person, reflect.TypeOf(person))
    fmt.Printf("unmarshalled value: %+v type: %+v\n", unmarshalledPerson, reflect.TypeOf(unmarshalledPerson))
    fmt.Printf("are variables equal: %v\n", reflect.DeepEqual(unmarshalledPerson, person))
}

Returns

struct value: {Name:John} type: main.Person
unmarshalled value: &{Name:John} type: *main.Person
are variables equal: false

The method genericUnmarshal returns a pointer to the type.

My question: Is there a way change the unmarshalled value into a struct (i.e. Person) instead of a pointer, so that reflect.DeepEqual(unmarshalledPerson, person) returns true?

icza
  • 289,344
  • 42
  • 658
  • 630
user18247
  • 31
  • 3

1 Answers1

2

You may compare person pointers, because reflect.DeepEqual() also accepts if the pointed values are (deeply) equal:

Pointer values are deeply equal if they are equal using Go's == operator or if they point to deeply equal values.

So simply do:

fmt.Printf("are variables equal: %v\n",
    reflect.DeepEqual(unmarshalledPerson, &person))

Or dereference the *Person pointer wrapped inside unmarshalledPerson so you get a Person struct:

fmt.Printf("are variables equal: %v\n",
    reflect.DeepEqual(*unmarshalledPerson.(*Person), person))

Both prints true (try it on the Go Playground):

are variables equal: true
are variables equal: true

Also note that for your "simple" struct you may use simple == comparison:

*unmarshalledPerson.(*Person) == person

This won't be the case if you add other fields such as pointers, structs, maps etc.

icza
  • 289,344
  • 42
  • 658
  • 630