8

Dave Cheney, one of the leading subject matter experts on Go, wrote: "When initializing a variable with a composite literal, Go requires that each line of the composite literal end with a comma, even the last line of your declaration. This is the result of the semicolon rule."

However, when I am trying to apply that beautiful rule to JSON text, the parser doesn't seem to agree with this philosophy. In the code below, removing the comma works. Is there a fix for this so I can just see one line change when I add elements in my diffs?

package main

import (
    "fmt"
    "encoding/json"
)

type jsonobject struct {
    Objects []ObjectType `json:"objects"`
}

type ObjectType struct {
    Name string `json:"name"`
}

func main() {
    bytes := []byte(`{ "objects": 
        [ 
            {"name": "foo"}, // REMOVE THE COMMA TO MAKE THE CODE WORK!
        ]}`)
    jsontype := &jsonobject{}
    json.Unmarshal(bytes, &jsontype)
    fmt.Printf("Results: %v\n", jsontype.Objects[0].Name) // panic: runtime error: index out of range
}
Grokify
  • 15,092
  • 6
  • 60
  • 81
John Difool
  • 5,572
  • 5
  • 45
  • 80

2 Answers2

6

There is not. The JSON specification does not allow a trailing comma.

This is not a valid JSON:

{ "objects": 
    [ 
        {"name": "foo"},
]}

It's a Go syntax that you need to use a comma if the enumeration is not closed on the line (more on this), e.g.:

// Slice literal:
s := []int {
    1,
    2,
}

// Function call:
fmt.Println(
    "Slice:",
    s,
)

Even if you could "convince" one specific JSON parser to silently swallow it, other, valid JSON parsers would report an error, rightfully. Don't do it.

Community
  • 1
  • 1
icza
  • 389,944
  • 63
  • 907
  • 827
3

While trailing commas are not valid JSON, some languages support trailing commas natively, notably JavaScript, so you may see them in your data.

It's better to remove trailing commas, but if you cannot change your data, use a JSON parser that supports trailing commas like HuJSON (aka Human JSON) which supports trailing commas and comments in JSON. It is maintained by noted Xoogler and Ex-Golang team member Brad Fitzpatrick and others.

In order to Unmarshal into arbitrary Go types, use:

b, err := hujson.Standardize(inputBytes)
if err != nil {
    ... // handle err
}

v := map[string]any{}
if err := json.Unmarshal(b, &v); err != nil {
    ... // handle err
}

I've used it and it works as described.

kubanczyk
  • 5,184
  • 1
  • 41
  • 52
Grokify
  • 15,092
  • 6
  • 60
  • 81