33

I'm playing with Go and am stumped as to why json encode and decode don't work for me

I think i copied the examples almost verbatim, but the output says both marshal and unmarshal return no data. They also don't give an error.

can anyone hint to where i'm going wrong?

my sample code: Go playground

package main

import "fmt"
import  "encoding/json"

type testStruct struct {
    clip string `json:"clip"`
}

func main() {
//unmarshal test
    var testJson = "{\"clip\":\"test\"}"
    var t testStruct
    var jsonData = []byte(testJson)
    err := json.Unmarshal(jsonData, &t)
    if err != nil {
        fmt.Printf("There was an error decoding the json. err = %s", err)
        return
    }
    fmt.Printf("contents of decoded json is: %#v\r\n", t)

//marshal test
    t.clip = "test2"
    data, err := json.Marshal(&t)
    if err != nil {
         fmt.Printf("There was an error encoding the json. err = %s", err)
         return
    }
    fmt.Printf("encoded json = %s\r\n", string(data))
}

output:

 contents of decoded json is: main.testStruct{clip:""}
 encoded json = {}

in both outputs I would have expected to see the decoded or encoded json

Toad
  • 15,593
  • 16
  • 82
  • 128
  • Possible duplicate of [JSON and dealing with unexported fields](https://stackoverflow.com/questions/11126793/json-and-dealing-with-unexported-fields) – Jonathan Hall May 13 '18 at 20:23

3 Answers3

52

For example,

package main

import "fmt"
import "encoding/json"

type testStruct struct {
    Clip string `json:"clip"`
}

func main() {
    //unmarshal test
    var testJson = "{\"clip\":\"test\"}"
    var t testStruct
    var jsonData = []byte(testJson)
    err := json.Unmarshal(jsonData, &t)
    if err != nil {
        fmt.Printf("There was an error decoding the json. err = %s", err)
        return
    }
    fmt.Printf("contents of decoded json is: %#v\r\n", t)

    //marshal test
    t.Clip = "test2"
    data, err := json.Marshal(&t)
    if err != nil {
        fmt.Printf("There was an error encoding the json. err = %s", err)
        return
    }
    fmt.Printf("encoded json = %s\r\n", string(data))
}

Output:

contents of decoded json is: main.testStruct{Clip:"test"}
encoded json = {"clip":"test2"}

Playground:

http://play.golang.org/p/3XaVougMTE

Export the struct fields.

type testStruct struct {
    Clip string `json:"clip"`
}

Exported identifiers

An identifier may be exported to permit access to it from another package. An identifier is exported if both:

  • the first character of the identifier's name is a Unicode upper case letter (Unicode class "Lu"); and
  • the identifier is declared in the package block or it is a field name or method name.

All other identifiers are not exported.

peterSO
  • 158,998
  • 31
  • 281
  • 276
  • 9
    wow... I knew about the uppercase thingy, but never realised it had any bearing on json encodability (is that a word?). Thanks for the missing insight – Toad Aug 31 '14 at 19:57
  • In edge cases where two keys in JSON are the same except that one is capitalized, this will result in chaos, as json.Unmarshal() always takes the last k-v pair regardless of it being capitalized or not. And obviously this is against http://jsonrpc.org/historical/json-rpc-1-1-alt.html#service-procedure-and-parameter-names. Is there any spec-compliant function for JSON deserialization? – Isilmë O. May 21 '18 at 07:35
  • 1
    @IsilmëO. I believe you could just do something like ``Clip string `json:"clip"` `` and ``OtherClip string `json:"Clip"` `` – Finster Jul 27 '18 at 14:27
  • 2
    Boy!.. I ran into this problem and spent half a day scratching my head. Did not realize that not uppercasing was the cause. – Shashi Jul 29 '20 at 08:12
30

Capitalize names of structure fields

type testStruct struct {
    clip string `json:"clip"` // Wrong.  Lowercase - other packages can't access it
}

Change to:

type testStruct struct {
    Clip string `json:"clip"`
}
Robert
  • 37,670
  • 37
  • 171
  • 213
Yurkol
  • 1,414
  • 1
  • 19
  • 28
1

In my case, my struct fields were capitalized but I was still getting the same error. Then I noticed that the casing of my fields was different. I had to use underscores in my request.

For eg: My request body was:

{
  "method": "register",
  "userInfo": {
    "fullname": "Karan",
    "email": "email@email.com",
    "password": "random"
  }
}

But my golang struct was:

type AuthRequest struct {
    Method   string   `json:"method,omitempty"`
    UserInfo UserInfo `json:"user_info,omitempty"`
}

I solved this by modifying my request body to:

{
  "method": "register",
  "user_info": {
    "fullname": "Karan",
    "email": "email@email.com",
    "password": "random"
  }
}
Karan Singh
  • 1,114
  • 1
  • 13
  • 30