json.Unmarshal nested object into string or []byte

20,208

Solution 1

I think what you are looking for is the RawMessage type in the encoding/json package.

The documentation states:

type RawMessage []byte

RawMessage is a raw encoded JSON object. It implements Marshaler and Unmarshaler and can be used to delay JSON decoding or precompute a JSON encoding.

Here is a working example of using RawMessage:

package main

import (
    "encoding/json"
    "fmt"
)

var jsonStr = []byte(`{
    "id"  : 15,
    "foo" : { "foo": 123, "bar": "baz" }
}`)

type Bar struct {
    Id  int64           `json:"id"`
    Foo json.RawMessage `json:"foo"`
}

func main() {
    var bar Bar

    err := json.Unmarshal(jsonStr, &bar)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%+v\n", bar)
}

Output:

{Id:15 Foo:[123 32 34 102 111 111 34 58 32 49 50 51 44 32 34 98 97 114 34 58 32 34 98 97 122 34 32 125]}

Playground

Solution 2

The Foo type is a map[string]string so define Foo correctly:

type Bar struct {
    id int64
    Foo map[string]string
}

Think that would work better

Solution 3

Defining a type which implements the Unmarshaler interface gives you access to the []byte's being parsed.

type Prefs []byte

func (p *Prefs) UnmarshalJSON(b []byte) error {
    *p = make(Prefs, len(b))
    copy(*p, b)
    return nil
}

playground demo

Share:
20,208

Related videos on Youtube

Ilia Choly
Author by

Ilia Choly

Favourite Languages: Go TypeScript Python C Lisp Interests: Networking Distributed/Parallel Computing Compilers Security Social Twitter Facebook Github

Updated on April 27, 2021

Comments

  • Ilia Choly
    Ilia Choly about 3 years

    I'm trying to Unmarshal some json so that a nested object does not get parsed but just treated as a string or []byte.

    So I want to get the following:

    {
        "id"  : 15,
        "foo" : { "foo": 123, "bar": "baz" }
    }
    

    Unmarshaled into:

    type Bar struct {
        ID  int64  `json:"id"`
        Foo []byte `json:"foo"`
    }
    

    I get the following error:

    json: cannot unmarshal object into Go value of type []uint8
    

    playground demo

    • J. Holmes
      J. Holmes over 10 years
      Why not use map[string]interface{}? It also has the advantage of re-Marshalling the correct way.
    • Adrian Forsius
      Adrian Forsius over 5 years
      @JamesHolmes this is usually not recommended since this allows for any type, if you don't explicitly want ALL types to be supported don't use empty interface (interface{}), it will cause you more problems than it will solve
  • Ilia Choly
    Ilia Choly over 10 years
    So []bytes -> Unmarshal -> map[string]interface{} -> Marshal -> string ... why ?
  • Ilia Choly
    Ilia Choly over 10 years
    that's exactly what I wanted
  • ANisus
    ANisus over 10 years
    Told you so ;) . Glad to help!
  • Ilia Choly
    Ilia Choly over 10 years
    I think this example better communicates what you're saying play.golang.org/p/1XFn6zqME8 . However, it doesn't really answer the question.
  • chovy
    chovy about 3 years
    i get that output, but how do I use it?