3

I'm making a Go service that gathers JSON objects from different sources and aggregates them in a single JSON object.

I was wondering if there was any way to aggregate the child objects without having to unmarshal and re-marshal them again or having to manually build a JSON string.

I was thinking of using a struct containing the already marshalled parts, such as this:

type Event struct {
    Place     string `json:"place"`
    Attendees string `json:"attendees"`
}

Where Place and Attendees are JSON strings themselves. I'd like to somehow mark them as "already marshalled" so they don't end up as escaped JSON strings but get used as is instead.

Is there any way to achieve this?

2 Answers 2

4

You can use json.RawMessage

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.

Also, json.RawMessage is an alias to []byte so you can values to it this way:

v := json.RawMessage(`{"foo":"bar"}`)

Example:

package main

import (
    "encoding/json"
    "fmt"
)

type Event struct {
    Place     json.RawMessage `json:"place"`
    Attendees json.RawMessage `json:"attendees"`
}

func main() {
    e := Event{
         Place: json.RawMessage(`{"address":"somewhere"}`),
         Attendees: json.RawMessage(`{"key":"value"}`),
    }
    c, err := json.Marshal(&e)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(c))
    // {"place":{"address":"somewhere"},"attendees":{"key":"value"}}
}
Sign up to request clarification or add additional context in comments.

4 Comments

I've tried to use RawMessage but it encodes the string to base64. Can you provide a working example? Just curious, as it was first what I tried.
I actually tried RawMessage as the contents I have really are []byte and not string and it gets encoded in base64 too. If there's a workaround for this...
@Jukurrpa, you can inherit your custom class as type RawBytes []byte. Also curios about RawMessage.
You must have passed the json.RawMessage by value and not a pointer. see stackoverflow.com/a/24229303/1826232
3

Yes, you can use a custom type that implements Marshaler interface.

https://play.golang.org/p/YB_eKlfOND

package main

import (
    "fmt"
    "encoding/json"
)

type Event struct {
    Place     RawString  `json:"place"`
    Attendees RawString  `json:"attendees,omitempty"`
}

type RawString string

func (s RawString) MarshalJSON() ([]byte, error) {
    return []byte(s), nil
}

func main() {
    event := Event{
        Place: RawString(`{"name":"Paris"}`),
        Attendees: RawString(`[{"name":"John"}, {"name":"Juli"}]`),
    }
    s, err := json.Marshal(event)
    fmt.Println(fmt.Sprintf("event: %v; err: %v", string(s), err))
}

1 Comment

@KarrotKake, the RawMessage was the first thing that I tried, but it encodes to base64. Do you have a working example? I would be happy to check where I did wrong.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.