As per the docs: https://golang.org/pkg/encoding/json/#Marshal
Array and slice values encode as JSON arrays, except that []byte encodes as a base64-encoded string, and a nil slice encodes as the null JSON object.
The value AAAAAQID is a base64 representation of your byte slice - e.g.
b, err := base64.StdEncoding.DecodeString("AAAAAQID")
if err != nil {
log.Fatal(err)
}
fmt.Printf("%v", b)
// Outputs: [0 0 0 1 2 3]
Answer from elithrar on Stack OverflowMarshaling JSON []byte as strings in Go - Stack Overflow
go - How to convert []byte slice into JSON GOLANG - Stack Overflow
Json encode byte array as hex string instead of base64
proposal: encoding/json: add a function to report whether a []byte represents a JSON array before unmarshal
If []byte really is what you want, use json.RawMessage, which is of type []byte, but also implements the methods for JSON parsing. I believe this may be what you want, as it will accept whatever ends up in data. Of course, you then have to manually parse Data to figure out just what actually IS in there.
One possible bonus is that this skips any heavy parsing because it just copies the bytes over. When you want to use this data for something, you use a []interface{}, then use a type switch to use individual values.
https://play.golang.org/p/og88qb_qtpSGJ
package main
import (
"encoding/json"
"fmt"
)
type Obj struct {
Id string `json:"id"`
Data json.RawMessage `json:"data"`
}
func main() {
byt := []byte(`{"id":"someID","data":["str1","str2", 1337, {"my": "obj", "id": 42}]}`)
var obj Obj
if err := json.Unmarshal(byt, &obj); err != nil {
panic(err)
}
fmt.Printf("%+v\n", obj)
fmt.Printf("Data: %s\n", obj.Data)
// use it
var d []interface{}
if err := json.Unmarshal(obj.Data, &d); err != nil {
panic(err)
}
fmt.Printf("%+v\n", d)
for _, v := range d {
// you need a type switch to deterine the type and be able to use most of these
switch real := v.(type) {
case string:
fmt.Println("I'm a string!", real)
case float64:
fmt.Println("I'm a number!", real)
default:
fmt.Printf("Unaccounted for: %+v\n", v)
}
}
}
My first recommendation would be for you to just use []string instead of []byte if you know the input type is going to be an array of strings.
If data is going to be a JSON array with various types, then your best option is to use []interface{} instead - Go will happily unmarshal the JSON for you and you can perform checks at runtime to cast those into more specific typed variables on an as-needed basis.
A []byte is marshalled as base64 encoded string. From the documentation:
Array and slice values encode as JSON arrays, except that
[]byteencodes as a base64-encoded string, and a nil slice encodes as the null JSON object.
These values are decoded properly when unmarshalled.
The reason why this is done is that JSON does not have a native representation for raw bytes. See this question for a detailed explanation.
I came a cross the same thing and even if this is a rather old question and already answered there is another option.
If you use json.RawMessage (which internaly is a []byte) as a type instead of []byte the Marshaling works into a Json String as expected.
Hi, I'm new-ish to golang, formerly a self-taught python hack. I can not figure out why I'm unable to read this (rather large ~130mb) json file. I'm really at my wits end here. Please help me understand whats going on if you can!
Here is an image showing a nil value of b at the breakpoint after I've tried to unmarshal the json file.
https://imgur.com/a/szpp4Ih
I did edit out my system name in the photo.
Here is the code:
func Jsp() {var b []bytejsonFile, err := os.Open(".../Downloads/drug-label-0008-of-0011.json")if err != nil {fmt.Println(err)}bytes, err := ioutil.ReadAll(jsonFile)if err != nil {fmt.Println(err)}json.Unmarshal(bytes, &b)fmt.Println(b)}
According to the docs, a []byte will be encoded as a Base64 string.
"Array and slice values encode as JSON arrays, except that []byte encodes as a base64-encoded string, and a nil slice encodes as the null JSON object."
So I think that you may need to make your struct implement the Marshaler interface by implementing your own MarshalJSON method that makes a more desirable JSON array encoding out of your []uint8.
Take this example:
import "fmt"
import "encoding/json"
import "strings"
type Test struct {
Name string
Array []uint8
}
func (t *Test) MarshalJSON() ([]byte, error) {
var array string
if t.Array == nil {
array = "null"
} else {
array = strings.Join(strings.Fields(fmt.Sprintf("%d", t.Array)), ",")
}
jsonResult := fmt.Sprintf(`{"Name":%q,"Array":%s}`, t.Name, array)
return []byte(jsonResult), nil
}
func main() {
t := &Test{"Go", []uint8{'h', 'e', 'l', 'l', 'o'}}
m, err := json.Marshal(t)
if err != nil {
fmt.Println(err)
}
fmt.Printf("%s", m) // {"Name":"Go","Array":[104,101,108,108,111]}
}
http://play.golang.org/p/Tip59Z9gqs
Or maybe a better idea would be to make a new type that has []uint8 as its underlying type, make that type a Marshaler, and use that type in your struct.
import "fmt"
import "encoding/json"
import "strings"
type JSONableSlice []uint8
func (u JSONableSlice) MarshalJSON() ([]byte, error) {
var result string
if u == nil {
result = "null"
} else {
result = strings.Join(strings.Fields(fmt.Sprintf("%d", u)), ",")
}
return []byte(result), nil
}
type Test struct {
Name string
Array JSONableSlice
}
func main() {
t := &Test{"Go", []uint8{'h', 'e', 'l', 'l', 'o'}}
m, err := json.Marshal(t)
if err != nil {
fmt.Println(err)
}
fmt.Printf("%s", m) // {"Name":"Go","Array":[104,101,108,108,111]}
}
http://play.golang.org/p/6aURXw8P5d
Here's another way, instead of using the slice []uint8, use the array [...]uint8:
marshal1, _ := json.Marshal([]uint8{32}) //"IA=="
marshal2, _ := json.Marshal([...]uint8{32}) //[32]
Also:
data := []uint8{32}
marshal, _ := json.Marshal((*[1]uint8)(data)) //after go1.17
marshal, _ := json.Marshal(*(*[1]uint8)(unsafe.Pointer(&data[0]))) //not recommended
Because go only treats byte slices specially (at least in the current version 1.23):
func newSliceEncoder(t reflect.Type) encoderFunc {
// Byte slices get special treatment; arrays don't.
if t.Elem().Kind() == reflect.Uint8 {
p := reflect.PointerTo(t.Elem())
if !p.Implements(marshalerType) && ! p.Implements(textMarshalerType) {
return encodeByteSlice
}
}
enc := sliceEncoder{newArrayEncoder(t)}
return enc.encode
}
I've json data in bytes. I wanted to append some fields to root of the byte data without doing Unmarshalling or Marshalling actions.
bt := []byte(`{"data": ["a", "b", "c"]}`)I wanted to add fields along side "data". Please suggest how could I achieve same without doing Unmarshalling/Marshalling
I am confused how Json is handled in Go.
why does it takes []bytes to unmarshal and just the struct to marshal?
also pls clarify how is json sent over network; in bytes, as string, or how?