Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What input will cause golang's json.Marshal to return an error?

From the docs:

JSON cannot represent cyclic data structures and Marshal does not handle them. Passing cyclic structures to Marshal will result in an infinite recursion.

I've experienced this situation, which results in a runtime panic.

What I'm wondering is if anyone can provide a working program that demonstrates a non-panic situation where json.Marshal returns a non-nil error. The best answers would clearly include the inputs used.

like image 556
mdwhatcott Avatar asked Nov 24 '15 20:11

mdwhatcott


People also ask

How does JSON marshal work?

Marshaling: Converting Go objects to JSON The Marshal function comes with the following syntax. It accepts an empty interface. In other words, you can provide any Go data type to the function — an integer, float, string, struct, map, etc. — because all Go data type definitions can be represented with empty interfaces.

What does Marshal mean JSON?

JSON has 3 basic types: booleans, numbers, strings, combined using arrays and objects to build complex structures. Go's terminology calls marshal the process of generating a JSON string from a data structure, and unmarshal the act of parsing JSON to a data structure.

How do I use Unmarshal JSON?

To parse JSON, we use the Unmarshal() function in package encoding/json to unpack or decode the data from JSON to a struct. Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v. Note: If v is nil or not a pointer, Unmarshal returns an InvalidUnmarshalError.

What does JSON NewDecoder do?

NewDecoder to "remove buffer in JSON decoding." It just depends on what input is more convenient for you to use. blog.golang.org/json-and-go gives examples of using both techniques. IMO, ioutil.


3 Answers

Just to complement Jonathan's answer, the json.Marshal function can return two types of errors: UnsupportedTypeError or UnsupportedValueError

The first one can be caused, as Jonathan said by trying to Marshal an invalid type:

_, err := json.Marshal(make(chan int))
_, ok := err.(*json.UnsupportedTypeError) // ok == true

On the other hand you can also have the Marshal function return an error by passing an invalid value:

_, err := json.Marshal(math.Inf(1))
_, ok := err.(*json.UnsupportedValueError) // ok == true
like image 80
hbejgel Avatar answered Oct 19 '22 19:10

hbejgel


Update: now using a channel instead of a map[int]int to elicit the error


Go-specific structures,e.g. func or chan refuse to serialize:

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    value := make(chan int)
    _, err := json.Marshal(value)
    fmt.Println(err)
}
like image 37
Jonathan Oliver Avatar answered Oct 19 '22 21:10

Jonathan Oliver


Read the source code you can found such a function to judge a encoder if not exist will return marshal error: https://github.com/golang/go/blob/master/src/encoding/json/encode.go

func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc {
    // ignored
    switch t.Kind() {
    case reflect.Bool:
        return boolEncoder
    case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
        return intEncoder
    case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
        return uintEncoder
    case reflect.Float32:
        return float32Encoder
    case reflect.Float64:
        return float64Encoder
    case reflect.String:
        return stringEncoder
    case reflect.Interface:
        return interfaceEncoder
    case reflect.Struct:
        return newStructEncoder(t)
    case reflect.Map:
        return newMapEncoder(t)
    case reflect.Slice:
        return newSliceEncoder(t)
    case reflect.Array:
        return newArrayEncoder(t)
    case reflect.Ptr:
        return newPtrEncoder(t)
    default:
        return unsupportedTypeEncoder
    }
}

We can find all kinds enum at https://github.com/golang/go/blob/master/src/reflect/type.go

So it's not hard to see that kinds not in above function are unable to marshal:

UnsafePointer,Complex64,Complex128,Chan,Func

Examples:

        json.Marshal(unsafe.Pointer(nil)) // UnsafePointer
        json.Marshal(complex64(1))        // Complex64
        json.Marshal(complex128(1))       // Complex128
        json.Marshal(make(chan struct{})) // Chan
        json.Marshal(func() {})           // Func
like image 43
AnonymousX Avatar answered Oct 19 '22 19:10

AnonymousX