Unmarshal JSON to Struct of Map - json

I have below program. I need to convert JSON data into object type cache which contains a single field of map[string]string type. There is something that I am doing wrong w.r.t. initialising map and unmarshalling JSON but unable to identify the syntax issue.
Note: I have marshalled data just for convenience sake to have sample JSON data.
package main
import (
"fmt"
"encoding/json"
"strconv"
)
const data = `{"Mode":{"ID-1":"ON","ID-2":"OFF","ID-3":"ON"}}`
type Cache struct {
Mode map[string]string `json:"Mode"`
}
func main() {
jsonData, _ := json.Marshal(data)
fmt.Println(strconv.Unquote(string(jsonData)))
var c Cache
c.Mode = make(map[string]string) //I want to initialise map so that I can store data in next step, but this is wrong I know
c.Mode["ID-4"] = "ON" //Want to store data like this
json.Unmarshal(jsonData, &c)
fmt.Println(c) //I am getting output as nil map i.e. {map[]}
for k, v := range c.Mode {
fmt.Println(k, v) //I am getting NO output i.e. blank
}
}

Here is your your code fixed https://play.golang.org/p/5ftaiz_Q5wl (attaching blow the copy)
package main
import (
"encoding/json"
"fmt"
"log"
)
const data = `{"Mode":{"ID-1":"ON","ID-2":"OFF","ID-3":"ON"}}`
type Cache struct {
Mode map[string]string `json:"Mode"`
}
func main() {
c := Cache{}
err := json.Unmarshal([]byte(data), &c)
if err != nil {
log.Println(err)
}
c.Mode["ID-4"] = "ON" //Want to store data like this
fmt.Println(c)
for k, v := range c.Mode {
fmt.Println(k, v)
}
}
Here is the output:
{map[ID-1:ON ID-2:OFF ID-3:ON ID-4:ON]}
ID-2 OFF
ID-3 ON
ID-4 ON
ID-1 ON

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)
}

Go Unmarshal reflect.Type got map[string]interface{}

I want to convert json string to some struct ,use as func param
I use reflect to get Param Type,this work fine ,
but if I use json.Unmarshal I always get map[string]interface{}
this is a mini Run sample,File name is json_test.go
package testJson
import (
"reflect"
"encoding/json"
"testing"
"log"
)
type LoginForm struct {
Name string
}
func Login(login LoginForm) {
}
func TestRun(t *testing.T) {
_func := Login
f := reflect.ValueOf(_func)
funcType := f.Type()
paramType := funcType.In(0)
log.Print(paramType.Name())
v := reflect.New(paramType).Elem().Interface()
jsonstr := `{"Name":"123"}`
log.Print(jsonstr)
log.Print(reflect.TypeOf(v).Name())
log.Print("%+v", v)
err := json.Unmarshal([]byte(jsonstr), &v)
if err != nil {
panic(err)
}
log.Print(reflect.TypeOf(v).Name())
log.Print( v)
var in []reflect.Value
in = make([]reflect.Value, funcType.NumIn())
in[0] = reflect.ValueOf(v)
f.Call(in)
}
Thanks for your help!
Don't reflect.New a pointer type because the result of that is a pointer to the pointer, instead reflect.New the Elem of the pointer type.
Change this:
v := reflect.New(paramType).Elem().Interface()
To this:
v := reflect.New(paramType.Elem()).Interface()
At this point v is already a pointer to LoginForm so you don't need to get its address with & when passing to Unmarshal.
https://play.golang.org/p/JM4fRXb7fo
Also the reason you got map[string]interface{} is because the return type of the Interface() method is unsurprisingly enough interface{}, so while v's underlying type could be anything its "topmost" type is interface{}. So then, doing &v will get you *interface{} as opposed to the inteded *LoginForm. And in the docs you can find that trying to unmarshal a JSON object into an interface{} will result in a value of type map[string]interface{}.

Write Struct to Json File using Struct Fields (not json keys)

How can I read a json file into a struct, and then Marshal it back out to a json string with the Struct fields as keys (rather than the original json keys)?
(see Desired Output to Json File below...)
Code:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
)
type Rankings struct {
Keyword string `json:"keyword"`
GetCount uint32 `json:"get_count"`
Engine string `json:"engine"`
Locale string `json:"locale"`
Mobile bool `json:"mobile"`
}
func main() {
var jsonBlob = []byte(`
{"keyword":"hipaa compliance form", "get_count":157, "engine":"google", "locale":"en-us", "mobile":false}
`)
rankings := Rankings{}
err := json.Unmarshal(jsonBlob, &rankings)
if err != nil {
// nozzle.printError("opening config file", err.Error())
}
rankingsJson, _ := json.Marshal(rankings)
err = ioutil.WriteFile("output.json", rankingsJson, 0644)
fmt.Printf("%+v", rankings)
}
Output on screen:
{Keyword:hipaa compliance form GetCount:157 Engine:google Locale:en-us Mobile:false}
Output to Json File:
{"keyword":"hipaa compliance form","get_count":157,"engine":"google","locale":"en-us","mobile":false}
Desired Output to Json File:
{"Keyword":"hipaa compliance form","GetCount":157,"Engine":"google","Locale":"en-us","Mobile":false}
If I understand your question correctly, all you want to do is remove the json tags from your struct definition.
So:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
)
type Rankings struct {
Keyword string
GetCount uint32
Engine string
Locale string
Mobile bool
}
func main() {
var jsonBlob = []byte(`
{"keyword":"hipaa compliance form", "get_count":157, "engine":"google", "locale":"en-us", "mobile":false}
`)
rankings := Rankings{}
err := json.Unmarshal(jsonBlob, &rankings)
if err != nil {
// nozzle.printError("opening config file", err.Error())
}
rankingsJson, _ := json.Marshal(rankings)
err = ioutil.WriteFile("output.json", rankingsJson, 0644)
fmt.Printf("%+v", rankings)
}
Results in:
{Keyword:hipaa compliance form GetCount:0 Engine:google Locale:en-us Mobile:false}
And the file output is:
{"Keyword":"hipaa compliance form","GetCount":0,"Engine":"google","Locale":" en-us","Mobile":false}
Running example at http://play.golang.org/p/dC3s37HxvZ
Note: GetCount shows 0, since it was read in as "get_count". If you want to read in JSON that has "get_count" vs. "GetCount", but output "GetCount" then you'll have to do some additional parsing.
See Go- Copy all common fields between structs for additional info about this particular situation.
Try to change the json format in the struct
type Rankings struct {
Keyword string `json:"Keyword"`
GetCount uint32 `json:"Get_count"`
Engine string `json:"Engine"`
Locale string `json:"Locale"`
Mobile bool `json:"Mobile"`
}
An accourance happened by just using json.Marshal() / json.MarshalIndent().
It overwrites the existing file, which in my case was suboptimal. I just wanted to add content to current file, and keep old content.
This writes data through a buffer, with bytes.Buffer type.
This is what I gathered up so far:
package srf
import (
"bytes"
"encoding/json"
"os"
)
func WriteDataToFileAsJSON(data interface{}, filedir string) (int, error) {
//write data as buffer to json encoder
buffer := new(bytes.Buffer)
encoder := json.NewEncoder(buffer)
encoder.SetIndent("", "\t")
err := encoder.Encode(data)
if err != nil {
return 0, err
}
file, err := os.OpenFile(filedir, os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
return 0, err
}
n, err := file.Write(buffer.Bytes())
if err != nil {
return 0, err
}
return n, nil
}
This is the execution of the function, together with the standard json.Marshal() or json.MarshalIndent() which overwrites the file
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
minerals "./minerals"
srf "./srf"
)
func main() {
//array of Test struct
var SomeType [10]minerals.Test
//Create 10 units of some random data to write
for a := 0; a < 10; a++ {
SomeType[a] = minerals.Test{
Name: "Rand",
Id: 123,
A: "desc",
Num: 999,
Link: "somelink",
People: []string{"John Doe", "Aby Daby"},
}
}
//writes aditional data to existing file, or creates a new file
n, err := srf.WriteDataToFileAsJSON(SomeType, "test2.json")
if err != nil {
log.Fatal(err)
}
fmt.Println("srf printed ", n, " bytes to ", "test2.json")
//overrides previous file
b, _ := json.MarshalIndent(SomeType, "", "\t")
ioutil.WriteFile("test.json", b, 0644)
}
Why is this useful?
File.Write() returns bytes written to the file! So this is perfect if you want to manage memory or storage.
WriteDataToFileAsJSON() (numberOfBytesWritten, error)

strict json parser in golang

In Go, I have some JSON from third-party API and then I'm trying to parse it:
b := []byte(`{"age":21,"married":true}`)
var response_hash map[string]string
_ = json.Unmarshal(b, &response_hash)
But it fails (response_hash becomes empty) and Unmarshal can handle only JSON with quotes:
b := []byte(`{"age":"21","married":"true"}`)
var response_hash map[string]string
_ = json.Unmarshal(b, &response_hash)
Is there any way to read the first version of JSON from third-party API?
Go is a strongly typed language. You need to specify what types the JSON encoder is to expect. You're creating a map of string values but your two json values are an integer and a boolean value.
Here's a working example with a struct.
http://play.golang.org/p/oI1JD1UUhu
package main
import (
"fmt"
"encoding/json"
)
type user struct {
Age int
Married bool
}
func main() {
src_json := []byte(`{"age":21,"married":true}`)
u := user{}
err := json.Unmarshal(src_json, &u)
if err != nil {
panic(err)
}
fmt.Printf("Age: %d\n", u.Age)
fmt.Printf("Married: %v\n", u.Married)
}
If you want to do it in a more dynamic manner you can use a map of interface{} values. You just have to do type assertions when you use the values.
http://play.golang.org/p/zmT3sPimZC
package main
import (
"fmt"
"encoding/json"
)
func main() {
src_json := []byte(`{"age":21,"married":true}`)
// Map of interfaces can receive any value types
u := map[string]interface{}{}
err := json.Unmarshal(src_json, &u)
if err != nil {
panic(err)
}
// Type assert values
// Unmarshal stores "age" as a float even though it's an int.
fmt.Printf("Age: %1.0f\n", u["age"].(float64))
fmt.Printf("Married: %v\n", u["married"].(bool))
}

Converting Go struct to JSON

I am trying to convert a Go struct to JSON using the json package but all I get is {}. I am certain it is something totally obvious but I don't see it.
package main
import (
"fmt"
"encoding/json"
)
type User struct {
name string
}
func main() {
user := &User{name:"Frank"}
b, err := json.Marshal(user)
if err != nil {
fmt.Printf("Error: %s", err)
return;
}
fmt.Println(string(b))
}
Then when I try to run it I get this:
$ 6g test.go && 6l -o test test.6 && ./test
{}
You need to export the User.name field so that the json package can see it. Rename the name field to Name.
package main
import (
"fmt"
"encoding/json"
)
type User struct {
Name string
}
func main() {
user := &User{Name: "Frank"}
b, err := json.Marshal(user)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(b))
}
Output:
{"Name":"Frank"}
Related issue:
I was having trouble converting struct to JSON, sending it as response from Golang, then, later catch the same in JavaScript via Ajax.
Wasted a lot of time, so posting solution here.
In Go:
// web server
type Foo struct {
Number int `json:"number"`
Title string `json:"title"`
}
foo_marshalled, err := json.Marshal(Foo{Number: 1, Title: "test"})
fmt.Fprint(w, string(foo_marshalled)) // write response to ResponseWriter (w)
In JavaScript:
// web call & receive in "data", thru Ajax/ other
var Foo = JSON.parse(data);
console.log("number: " + Foo.number);
console.log("title: " + Foo.title);
This is an interesting question, it is very easy using the new go versions. You should do this:
package main
import (
"fmt"
"encoding/json"
)
type User struct {
Name string `json:"name"`
}
func main() {
user := &User{name:"Frank"}
b, err := json.Marshal(user)
if err != nil {
fmt.Printf("Error: %s", err)
return;
}
fmt.Println(string(b))
}
Change this name to Name.
You can define your own custom MarshalJSON and UnmarshalJSON methods and intentionally control what should be included, ex:
package main
import (
"fmt"
"encoding/json"
)
type User struct {
name string
}
func (u *User) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
Name string `json:"name"`
}{
Name: "customized" + u.name,
})
}
func main() {
user := &User{name: "Frank"}
b, err := json.Marshal(user)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(b))
}
Struct values encode as JSON objects. Each exported struct field becomes
a member of the object unless:
the field's tag is "-", or
the field is empty and its tag specifies the "omitempty" option.
The empty values are false, 0, any nil pointer or interface value, and any array, slice, map, or string of length zero. The object's default key string is the struct field name but can be specified in the struct field's tag value. The "json" key in the struct field's tag value is the key name, followed by an optional comma and options.