Go: Assigning to nested struct - json

Below is a code snippet - I am confused as to how to assign to variables within my nested struct ("myTime") which I am using for JSON decoding. (I have some Unix timestamps in a JSON file and am hoping to learn how to decode them.)
This throws the following error:
main.go:15: cannot use time.Unix(a, 0) (type time.Time) as type *myTime in assignment
main.go:25: t.String undefined (type myTime has no field or method String)
I'm not sure exactly how to go about understanding the issue, so any explanation or a pointer to specific documentation would help greatly!
package main
import (
"encoding/binary"
"encoding/json"
"fmt"
"log"
"time"
)
type myTime time.Time
func (t *myTime) UnmarshalJSON(buf []byte) error {
a, _ := binary.Varint(buf)
t = time.Unix(a, 0)
return nil
}
func main() {
var t myTime
if err := json.Unmarshal([]byte("123123123.123123"), &t); err != nil {
log.Fatal(err)
}
fmt.Printf("result: %f\n", t.String())
}

time.Unix returns a time.Time value (not pointer)
so just do *t = myTime(time.Unix(a,0))
This basically assigns the value returned from time.Unix(a,0) to the value pointed to by t
as for String, you have to make your own:
func (m myTime) String() string { return time.Time(m).String() }
This is because when you alias a type, you do not inherit its method set.
so you must declare any method you want yourself.

Related

json.Unmarshal interface pointer with later type assertion

Because I often unmarshal http.Response.Body, I thought I could write a function which handles all the hassle of reading, closing and unmarshaling into various different structs. That's why I introduced a function func unmarhalInterface(closer *io.ReadCloser, v *interface{}) error and can then assert the return value with t:=i.(T).
According to this answer I already wrapped it into a value of type *interface{}, but because the overlying type is interface{}and not myStruct, the json package implementation chooses map[string]interface{}. After that a type assertion fails (of course). Is there anything i am missing or requires this implementation a type assertion "by hand", that means look for all fields in the map and assign those that I want into my struct.
Code below has minimal example with notation in comments. If my explanation is not sufficient, please ask away.
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
)
type myStruct struct {
A string `json:"a"`
B string `json:"b"`
}
func main() {
jsonBlob := []byte(`{"a":"test","b":"test2"}`)
var foo = interface{}(myStruct{})
closer := ioutil.NopCloser(bytes.NewReader(jsonBlob))
err := unmarshalCloser(&closer, &foo)
if err != nil {
log.Fatal(err)
}
fmt.Println(fmt.Sprintf("%v", foo))
// That´s what i want:
foo2 := foo.(myStruct)
fmt.Println(foo2.A)
}
func unmarshalCloser(closer *io.ReadCloser, v *interface{}) error {
defer func() { _ = (*closer).Close() }()
data, err := ioutil.ReadAll(*closer)
if err != nil {
return err
}
err = json.Unmarshal(data, v)
if err != nil {
return err
}
return nil
}
Golang Playground
An empty interface isn't an actual type, it's basically something that matches anything. As stated in the comments, a pointer to an empty interface doesn't really make sense as a pointer already matches an empty interface since everything matches an empty interface. To make your code work, you should remove the interface wrapper around your struct, since that's just messing up the json type checking, and the whole point of an empty interface is that you can pass anything to it.
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
)
type myStruct struct {
A string `json:"a"`
B string `json:"b"`
}
func main() {
jsonBlob := []byte(`{"a":"test","b":"test2"}`)
var foo = &myStruct{} // This need to be a pointer so its attributes can be assigned
closer := ioutil.NopCloser(bytes.NewReader(jsonBlob))
err := unmarshalCloser(closer, foo)
if err != nil {
log.Fatal(err)
}
fmt.Println(fmt.Sprintf("%v", foo))
// That´s what i want:
fmt.Println(foo.A)
}
// You don't need to declare either of these arguments as pointers since they're both interfaces
func unmarshalCloser(closer io.ReadCloser, v interface{}) error {
defer closer.Close()
// v NEEDS to be a pointer or the json stuff will barf
// Simplified with the decoder
return json.NewDecoder(closer).Decode(v)
}

Unmarshal json null into Pointer of NullString

I am unable to json.Unmarshal a null value into a *NullString field within a struct. Here is a simplified example of what I mean:
package main
import (
"database/sql"
"encoding/json"
"log"
)
// NullString
type NullString struct {
sql.NullString
}
func (n *NullString) UnmarshalJSON(b []byte) error {
n.Valid = string(b) != "null"
e := json.Unmarshal(b, &n.String)
return e
}
type Person struct {
Name *NullString `json:"name"`
}
func BuildUpdateSQL(jsonString string) string {
p := Person{}
e := json.Unmarshal([]byte(jsonString),&p)
if e != nil {
log.Println(e)
}
if p.Name != nil {
log.Println(p,p.Name)
} else {
log.Println(p)
}
return ""
}
func main() {
// Correctly leaves p.Name unset
BuildUpdateSQL(`{"field_not_exist":"samantha"}`)
// Correctly sets p.Name
BuildUpdateSQL(`{"name":"samantha"}`)
// Incorrectly leaves p.Name as nil when I really want p.Name to have a NullString with .Valid == false
BuildUpdateSQL(`{"name":null}`)
}
As you can see, unmarshalling works for non-null json values. But when I pass in a null json value, the NullString unmarshaller doesn't seem to even fire.
Anyone know what I'm doing wrong?
Background
The reason I'm trying to do this is because I plan to get JSON value from a REST API. Not all fields in the API are required fields. Hence I use pointers for my struct fields to help me build my SQL Update statement because:
field with nil means not populated (do not include a SET name = ?)
non-nil NullString.Valid == false means actual null value (include a SET name = NULL)
and non-nil NullString.Valid == true means a real string value exists (include a SET name = ?)
Yes, this is because of the following unmarshaling rule:
To unmarshal JSON into a pointer, Unmarshal first handles the case of the JSON being the JSON literal null. In that case, Unmarshal sets the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into the value pointed at by the pointer.
(Documentation for encoding/json).
What I suggest to do is to add a Set field which is changed to true when UnmarshalJSON is fired (which if there is any value, is guaranteed to be fired), and then to change the *NullString to a simple NullString, like so:
package main
import (
"database/sql"
"encoding/json"
"log"
)
// NullString
type NullString struct {
Set bool
sql.NullString
}
func (n *NullString) UnmarshalJSON(b []byte) error {
n.Set = true
n.Valid = string(b) != "null"
e := json.Unmarshal(b, &n.String)
return e
}
type Person struct {
Name NullString `json:"name"`
}
func BuildUpdateSQL(jsonString string) string {
p := Person{}
e := json.Unmarshal([]byte(jsonString), &p)
if e != nil {
log.Println(e)
}
log.Printf("%#v", p)
return ""
}
func main() {
BuildUpdateSQL(`{"field_not_exist":"samantha"}`)
BuildUpdateSQL(`{"name":"samantha"}`)
BuildUpdateSQL(`{"name":null}`)
}
Playground

Go: Converting JSON string to map[string]interface{}

I'm trying to create a JSON representation within Go using a map[string]interface{} type. I'm dealing with JSON strings and I'm having a hard time figuring out how to avoid the JSON unmarshaler to automatically deal with numbers as float64s. As a result the following error occurs.
Ex.
"{ 'a' : 9223372036854775807}" should be map[string]interface{} = [a 9223372036854775807 but in reality it is map[string]interface{} = [a 9.2233720368547758088E18]
I searched how structs can be used to avoid this by using json.Number but I'd really prefer using the map type designated above.
The go json.Unmarshal(...) function automatically uses float64 for JSON numbers. If you want to unmarshal numbers into a different type then you'll have to use a custom type with a custom unmarshaler. There is no way to force the unmarshaler to deserialize custom values into a generic map.
For example, here's how you could parse values of the "a" property as a big.Int.
package main
import (
"encoding/json"
"fmt"
"math/big"
)
type MyDoc struct {
A BigA `json:"a"`
}
type BigA struct{ *big.Int }
func (a BigA) UnmarshalJSON(bs []byte) error {
_, ok := a.SetString(string(bs), 10)
if !ok {
return fmt.Errorf("invalid integer %s", bs)
}
return nil
}
func main() {
jsonstr := `{"a":9223372036854775807}`
mydoc := MyDoc{A: BigA{new(big.Int)}}
err := json.Unmarshal([]byte(jsonstr), &mydoc)
if err != nil {
panic(err)
}
fmt.Printf("OK: mydoc=%#v\n", mydoc)
// OK: mydoc=main.MyDoc{A:9223372036854775807}
}
func jsonToMap(jsonStr string) map[string]interface{} {
result := make(map[string]interface{})
json.Unmarshal([]byte(jsonStr), &result)
return result
}
Example - https://goplay.space/#ra7Gv8A5Heh
Related questions - create a JSON data as map[string]interface with the given data

json.Unmarshal fails when embedded type has UnmarshalJSON

I'm trying to unmarshal a struct that has an embedded type. When the embedded type has an UnmarshalJSON method, the unmarshaling of the outer type fails:
https://play.golang.org/p/Y_Tt5O8A1Q
package main
import (
"fmt"
"encoding/json"
)
type Foo struct {
EmbeddedStruct
Field string
}
func (d *Foo) UnmarshalJSON(from []byte) error {
fmt.Printf("Foo.UnmarshalJSON\n")
type Alias Foo
alias := &Alias{}
if err := json.Unmarshal(from, alias); err != nil {
return fmt.Errorf("Error in Foo.UnmarshalJSON: json.Unmarshal returned an error:\n%v\n", err)
}
*d = Foo(*alias)
return nil
}
type EmbeddedStruct struct {
EmbeddedField string
}
func (d *EmbeddedStruct) UnmarshalJSON(from []byte) error {
fmt.Printf("EmbeddedStruct.UnmarshalJSON\n")
type Alias EmbeddedStruct
alias := &Alias{}
if err := json.Unmarshal(from, alias); err != nil {
return fmt.Errorf("Error in EmbeddedStruct.UnmarshalJSON: json.Unmarshal returned an error:\n%v\n", err)
}
*d = EmbeddedStruct(*alias)
return nil
}
func main() {
data := `{"EmbeddedField":"embeddedValue", "Field": "value"}`
foo := &Foo{}
json.Unmarshal([]byte(data), foo)
fmt.Printf("Foo: %v\n", foo)
if foo.EmbeddedField != "embeddedValue" {
fmt.Printf("Unmarshal didn't work, EmbeddedField value is %v. Should be 'embeddedValue'\n", foo.EmbeddedField)
}
if foo.Field != "value" {
fmt.Printf("Unmarshal didn't work, Field value is %v. Should be 'value'\n", foo.Field)
}
}
The output is:
Foo.UnmarshalJSON
EmbeddedStruct.UnmarshalJSON
Foo: &{{embeddedValue} }
Unmarshal didn't work, Field value is . Should be 'value'
... so both custom unmarshal functions ran. The value from the embedded struct is correct, but the value from the outer struct is lost.
If we simply remove the EmbeddedStruct.UnmarshalJSON method, it works as expected.
Am I doing something wrong? Is this expected? Or a bug? I'm sure there's a way I can tweak my UnmarshalJSON methods to get it working.
It is expected.
When you create the alias:
type Alias Foo
Alias will not inherit the methods of Foo since it is a different type with a different method set, which is what you wanted to achieve to avoid an infinite recursion.
However, the embedded EmbeddedStruct's UnmarshalJSON method will instead be promoted!
So, Alias will have an UnmarshalJSON method that will only unmarshal EmbeddedStruct's value, instead of using the default unmarshalling that you desired.

Can someone explain this interface example in Go?

From http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go there an example illustrating a possible use of interfaces in Go. Code as below:
package main
import (
"encoding/json"
"fmt"
"reflect"
"time"
)
// start with a string representation of our JSON data
var input = `
{
"created_at": "Thu May 31 00:00:01 +0000 2012"
}
`
type Timestamp time.Time
func (t *Timestamp) UnmarshalJSON(b []byte) error {
v, err := time.Parse(time.RubyDate, string(b[1:len(b)-1]))
if err != nil {
return err
}
*t = Timestamp(v)
return nil
}
func main() {
// our target will be of type map[string]interface{}, which is a pretty generic type
// that will give us a hashtable whose keys are strings, and whose values are of
// type interface{}
var val map[string]Timestamp
if err := json.Unmarshal([]byte(input), &val); err != nil {
panic(err)
}
fmt.Println(val)
for k, v := range val {
fmt.Println(k, reflect.TypeOf(v))
}
fmt.Println(time.Time(val["created_at"]))
}
with a result like this:
map[created_at:{63474019201 0 0x59f680}]
created_at main.Timestamp
2012-05-31 00:00:01 +0000 UTC
I am struggling to understand how the function call
json.Unmarshal([]byte(input), &val){...}
relates to the method defined earlier
func (t *Timestamp) UnmarshalJSON(b []byte) error{...}
Reading the doc at http://golang.org/pkg/encoding/json/#Unmarshal is confusing me even more.
I am obviously missing something here, but I can't figure it out.
In Go an interface is implemented just by implementing its methods. It is so much different from the most other popular languages (Java, C#, C++) in which the class interfaces should be explicitly mentioned in the class declaration.
The detailed explanation of this concept you can find in the Go documentation: https://golang.org/doc/effective_go.html#interfaces
So the func (t *Timestamp) UnmarshalJSON(...) defines a method and in a same time implements the interface. The json.Unmarshal then type asserts the elements of val to the Unmarshaler interface (http://golang.org/pkg/encoding/json/#Unmarshaler) and call the UnmarshalJSON method to construct them from the byte slice.