Skip to content

Discrepancy with "encoding/json" in handling null/missing RawMessage #166

Closed
@mdaffin

Description

@mdaffin

The following program demonstrates the issue:

package main                                                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                                 
import (                                                                                                                                                                                                                                                                         
        "encoding/json"                                                                                                                                                                                                                                                          
        "fmt"                                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                 
        "github.com/json-iterator/go"                                                                                                                                                                                                                                            
)                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                 
type A struct {                                                                                                                                                                                                                                                                  
        Raw json.RawMessage `json:"raw"`                                                                                                                                                                                                                                         
}                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                 
type B struct {                                                                                                                                                                                                                                                                  
        Raw jsoniter.RawMessage `json:"raw"`                                                                                                                                                                                                                                     
}                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                 
func main() {                                                                                                                                                                                                                                                                    
        message := []byte(`{}`)                                                                                                                                                                                                                                           
                                                                                                                                                                                                                                                                                 
        a := A{}                                                                                                                                                                                                                                                                 
        aerr := json.Unmarshal(message, &a)                                                                                                                                                                                                                                      
        aout, aouterr := json.Marshal(&a)                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                                 
        fmt.Printf("json:\n  a:%#v\n  aout: %s\n  aerr: %s\n  aouterr: %s\n\n", a, aout, aerr, aouterr)                                                                                                                                                                              
                                                                                                                                                                                                                                                                                 
        b := B{}                                                                                                                                                                                                                                                                 
        berr := jsoniter.Unmarshal(message, &b)                                                                                                                                                                                                                                  
        bout, bouterr := jsoniter.Marshal(&b)                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                 
        fmt.Printf("jsoniter:\n  b:%#v\n  bout: %s\n  berr: %s\n  bouterr: %s\n", b, bout, berr, bouterr)                                                                                                                                                                          
}                                                                                                                                                                                                                                                                                

Output:

json:
  a:main.A{Raw:json.RawMessage(nil)}
  aout: {"raw":null}
  aerr: %!s(<nil>)
  aouterr: %!s(<nil>)

jsoniter:
  b:main.B{Raw:jsoniter.RawMessage(nil)}
  bout: {"raw":}
  berr: %!s(<nil>)
  bouterr: %!s(<nil>)

Here jsoniter produces invalid json where encoding/json produces the correct result.

Note that the behaviour also varies when invalid json is in the message such as {"raw": invalid}. Although users should be handling the err in this case.

json:
  a:main.A{Raw:json.RawMessage(nil)}
  aout: {"raw":null}
  aerr: invalid character 'i' looking for beginning of value
  aouterr: %!s(<nil>)

jsoniter:
  b:main.B{Raw:jsoniter.RawMessage{0x20, 0x69}}
  bout: {"raw": i}
  berr: main.B: Raw: Skip: do not know how to skip: 105, parsing 9 ...{"raw": i... at {"raw": invalid}
  bouterr: %!s(<nil>)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions