Viet Phan
Viet Phan

Reputation: 2119

Marshal int slice to string line

I have a struct as this:

type Int64Slice []int64
type DataWrapper struct {
    ListId Int64Slice    `json:"listid" required`
    Domain string `json:"domain" required`
    Name   string `json:"name,omitempty"`
}

And I need it become:

{
    "listid": "1 2 3 4 5",
    "domain": "mydomain"
}

I have wrote custom MarshalJSON:

func (u Int64Slice) MarshalJSON() ([]byte, error) {
    var result string
    if u == nil {
        result = "null"
    } else {
        result = strings.Trim(strings.Join(strings.Fields(fmt.Sprint(u)), " "), "[]")
        Logger.Debugln(result)
    }
    return []byte(result), nil
}

func (d *DataWrapper) ToJSON() []byte {
    result, err := json.Marshal(d)
    if err != nil {
        log.Fatalln(err)
        panic(err)
    }
    return result
}

At the line Logger.Debugln(result), it prints this result:

20170830090317506 20170830090026319 20170830111023194 201708301043081 ...

json: error calling MarshalJSON for type models.Int64Slice: invalid character '2' after top-level value

Upvotes: 0

Views: 1211

Answers (2)

Jonathan Hall
Jonathan Hall

Reputation: 79586

20170830090317506 20170830090026319 20170830111023194 201708301043081 is not a valid JSON value. It is interpreted as a valid number (20170830090317506) followed by a valid space, followed by invalid data, beginning with the 2 character; thus the error you observed.

It needs quotes around it:

Try something like:

result = `"` + strings.Trim(strings.Join(strings.Fields(fmt.Sprint(u)), " "), "[]") + `"`

Upvotes: 2

kostix
kostix

Reputation: 55453

I think you have it backwards. Use the bytes.Buffer type to incrementally build up the string representation of your data.

The program

package main

import (
    "bytes"
    "encoding/json"
    "os"
    "strconv"
)

type Int64Slice []int64

func (s Int64Slice) MarshalJSON() ([]byte, error) {
    if s == nil {
        return []byte("null"), nil
    }

    var b bytes.Buffer
    b.WriteByte('"')
    for i, v := range s {
        if i > 0 {
            b.WriteByte('\x20')
        }
        b.WriteString(strconv.FormatInt(v, 10))
    }

    b.WriteByte('"')
    return b.Bytes(), nil
}

func main() {
    var (
        a Int64Slice = nil
        b = Int64Slice{
            42,
            12,
            0,
        }
    )
    enc := json.NewEncoder(os.Stdout)
    enc.Encode(a)
    enc.Encode(b)
}

Prints:

null
"42 12 0"

Playground link.

Upvotes: 2

Related Questions