Skip to content
This repository was archived by the owner on Dec 15, 2025. It is now read-only.
This repository was archived by the owner on Dec 15, 2025. It is now read-only.

Unable to unmarshal date using json-iterator. #313

Closed

Description

@aafreensheikh96

I am trying to use a custom struct which implements the json.Unmarshaler interface as a key in a map(map[MyCustomType]bool). This fails when I am trying to use jsoniter but works correctly if I use the standard library json package. Minimal code example to reproduce the issue:

package main

import (
    "encoding/json"
    "fmt"
    "time"

    jsoniter "github.com/json-iterator/go"
)

type Date struct {
    time.Time
}

func (d *Date) UnmarshalJSON(b []byte) error {
    dateStr := string(b) // something like `"2017-08-20"`

    if dateStr == "null" {
        return nil
    }

    t, err := time.Parse(`"2006-01-02"`, dateStr)
    if err != nil {
        return fmt.Errorf("cant parse date: %#v", err)
    }

    d.Time = t
    return nil
}

func main() {
    data := []byte(`{
        "2018-12-12": true,
        "2018-12-13": true,
        "2018-12-14": true
    }`)

    v := map[Date]bool{}
    if err := json.Unmarshal(data, &v); err != nil {
        panic(fmt.Errorf("standard library unmarshal: %+v", err))
    }

    fmt.Printf("Unmarshalled value using standard library: %+v\n", v)

    if err := jsoniter.Unmarshal(data, &v); err != nil {
        panic(fmt.Errorf("jsoniter unmarshal: %+v", err))
    }

    fmt.Printf("%#v\n", v)
}

Output:

Unmarshalled value using standard library: map[2018-12-14 00:00:00 +0000 UTC:true 2018-12-12 00:00:00 +0000 UTC:true 2018-12-13 00:00:00 +0000 UTC:true]
panic: jsoniter unmarshal: textUnmarshalerDecoder: parsing time "2018-12-12" as "2006-01-02T15:04:05Z07:00": cannot parse "" as "T", error found in #10 byte of ...|018-12-12": true,
  |..., bigger context ...|{
        "2018-12-12": true,
        "2018-12-13": true,
        "2018-|...

Activity

  1. aafreensheikh96 commented on Oct 16, 2018

    @aafreensheikh96
    Author

    Doesn't still work on the latest version = "1.1.5"

  2. shatil commented on Oct 19, 2018

    @shatil

    @aafreensheikh96 wow, jsoniter doesn't call Date.UnmarshalJSON at all, whereas encoding/json calls it three times, as expected.

    (dlv) bp
    Breakpoint unrecovered-panic at 0x102e760 for runtime.fatalpanic() /usr/local/Cellar/go/1.11.1/libexec/src/runtime/panic.go:681 (1)
    	print runtime.curg._panic.arg
    Breakpoint 1 at 0x11b8a3b for main.(*Date).UnmarshalJSON() ./main.go:15 (3)
    Breakpoint jsoniter at 0x11b908d for main.main() ./main.go:45 (1)
    

    Using Delve with your main.go in the current directory:

    $ dlv debug
    Type 'help' for list of commands.
    (dlv) break Date.UnmarshalJSON
    Breakpoint 1 set at 0x11b8a3b for main.(*Date).UnmarshalJSON() ./main.go:15
    (dlv) break jsoniter main.go:45
    Breakpoint jsoniter set at 0x11b908d for main.main() ./main.go:45
    

    Then running it:

    (dlv) continue
    > main.(*Date).UnmarshalJSON() ./main.go:15 (hits goroutine(1):1 total:1) (PC: 0x11b8a3b)
        10:
        11:	type Date struct {
        12:		time.Time
        13:	}
        14:
    =>  15:	func (d *Date) UnmarshalJSON(b []byte) error {
        16:		dateStr := string(b) // something like `"2017-08-20"`
        17:
        18:		if dateStr == "null" {
        19:			return nil
        20:		}
    (dlv) continue
    > main.(*Date).UnmarshalJSON() ./main.go:15 (hits goroutine(1):2 total:2) (PC: 0x11b8a3b)
        10:
        11:	type Date struct {
        12:		time.Time
        13:	}
        14:
    =>  15:	func (d *Date) UnmarshalJSON(b []byte) error {
        16:		dateStr := string(b) // something like `"2017-08-20"`
        17:
        18:		if dateStr == "null" {
        19:			return nil
        20:		}
    (dlv) continue
    > main.(*Date).UnmarshalJSON() ./main.go:15 (hits goroutine(1):3 total:3) (PC: 0x11b8a3b)
        10:
        11:	type Date struct {
        12:		time.Time
        13:	}
        14:
    =>  15:	func (d *Date) UnmarshalJSON(b []byte) error {
        16:		dateStr := string(b) // something like `"2017-08-20"`
        17:
        18:		if dateStr == "null" {
        19:			return nil
        20:		}
    (dlv) continue
    Unmarshalled value using standard library: map[2018-12-13 00:00:00 +0000 UTC:true 2018-12-14 00:00:00 +0000 UTC:true 2018-12-12 00:00:00 +0000 UTC:true]
    > [jsoniter] main.main() ./main.go:45 (hits goroutine(1):1 total:1) (PC: 0x11b908d)
        40:			panic(fmt.Errorf("standard library unmarshal: %+v", err))
        41:		}
        42:
        43:		fmt.Printf("Unmarshalled value using standard library: %+v\n", v)
        44:
    =>  45:		if err := jsoniter.Unmarshal(data, &v); err != nil {
        46:			panic(fmt.Errorf("jsoniter unmarshal: %+v", err))
        47:		}
        48:
        49:		fmt.Printf("%#v\n", v)
        50:	}
    (dlv) continue
    > [unrecovered-panic] runtime.fatalpanic() /usr/local/Cellar/go/1.11.1/libexec/src/runtime/panic.go:681 (hits goroutine(1):1 total:1) (PC: 0x102e760)
    Warning: debugging optimized function
    	runtime.curg._panic.arg: interface {}(string) "jsoniter unmarshal: textUnmarshalerDecoder: parsing time \"2018-1...+214 more"
       676:	// fatalpanic implements an unrecoverable panic. It is like fatalthrow, except
       677:	// that if msgs != nil, fatalpanic also prints panic messages and decrements
       678:	// runningPanicDefers once main is blocked from exiting.
       679:	//
       680:	//go:nosplit
    => 681:	func fatalpanic(msgs *_panic) {
       682:		pc := getcallerpc()
       683:		sp := getcallersp()
       684:		gp := getg()
       685:		var docrash bool
       686:		// Switch to the system stack to avoid any stack growth, which
    
  3. sudo-suhas commented on Oct 24, 2018

    @sudo-suhas

    @shatil Please note that unmarshaling works correctly when the Date data type is used as a value like so:

    type myType struct {
    	Date Date   `json:"date"`
    	Text string `json:"text"`
    }
  4. sudo-suhas commented on Oct 27, 2018

    @sudo-suhas

    Thank you @taowen

  5. added a commit that references this issue on Feb 2, 2022
    9ec4cb8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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