mirror of
https://github.com/netbirdio/easyjson.git
synced 2026-05-22 18:44:42 -07:00
Feature: allow to unmarshal json.Number
Both go native encoding/json json.Unmarshal and ffjson's UnmarshalJSON methods could unmarshal both json-encoded strings:
`{"number": 10}`
`{"number": "20"}`
to struct {
Number json.Number `json:"number"`
}
But easyjson got error on unmarshaling second string.
This commit is contained in:
+8
-1
@@ -48,6 +48,10 @@ var primitiveStringDecoders = map[reflect.Kind]string{
|
||||
reflect.Uint64: "in.Uint64Str()",
|
||||
}
|
||||
|
||||
var customDecoders = map[string]string{
|
||||
"json.Number": "in.JsonNumber()",
|
||||
}
|
||||
|
||||
// genTypeDecoder generates decoding code for the type t, but uses unmarshaler interface if implemented by t.
|
||||
func (g *Generator) genTypeDecoder(t reflect.Type, out string, tags fieldTags, indent int) error {
|
||||
ws := strings.Repeat(" ", indent)
|
||||
@@ -82,7 +86,10 @@ func (g *Generator) genTypeDecoder(t reflect.Type, out string, tags fieldTags, i
|
||||
func (g *Generator) genTypeDecoderNoCheck(t reflect.Type, out string, tags fieldTags, indent int) error {
|
||||
ws := strings.Repeat(" ", indent)
|
||||
// Check whether type is primitive, needs to be done after interface check.
|
||||
if dec := primitiveStringDecoders[t.Kind()]; dec != "" && tags.asString {
|
||||
if dec := customDecoders[t.String()]; dec != "" {
|
||||
fmt.Fprintln(g.out, ws+out+" = "+dec)
|
||||
return nil
|
||||
} else if dec := primitiveStringDecoders[t.Kind()]; dec != "" && tags.asString {
|
||||
fmt.Fprintln(g.out, ws+out+" = "+g.getType(t)+"("+dec+")")
|
||||
return nil
|
||||
} else if dec := primitiveDecoders[t.Kind()]; dec != "" {
|
||||
|
||||
@@ -6,6 +6,7 @@ package jlexer
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -1043,6 +1044,28 @@ func (r *Lexer) GetNonFatalErrors() []*LexerError {
|
||||
return r.multipleErrors
|
||||
}
|
||||
|
||||
// JsonNumber fetches and json.Number from 'encoding/json' package.
|
||||
// Both int, float or string, contains them are valid values
|
||||
func (r *Lexer) JsonNumber() json.Number {
|
||||
if r.token.kind == tokenUndef && r.Ok() {
|
||||
r.FetchToken()
|
||||
}
|
||||
if !r.Ok() {
|
||||
r.errInvalidToken("json.Number")
|
||||
return json.Number("0")
|
||||
}
|
||||
|
||||
switch r.token.kind {
|
||||
case tokenString:
|
||||
return json.Number(r.String())
|
||||
case tokenNumber:
|
||||
return json.Number(r.Raw())
|
||||
default:
|
||||
r.errSyntax()
|
||||
return json.Number("0")
|
||||
}
|
||||
}
|
||||
|
||||
// Interface fetches an interface{} analogous to the 'encoding/json' package.
|
||||
func (r *Lexer) Interface() interface{} {
|
||||
if r.token.kind == tokenUndef && r.Ok() {
|
||||
|
||||
@@ -2,6 +2,7 @@ package jlexer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
@@ -249,3 +250,62 @@ func TestConsumed(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJsonNumber(t *testing.T) {
|
||||
for i, test := range []struct {
|
||||
toParse string
|
||||
want json.Number
|
||||
wantLexerError bool
|
||||
wantValue interface{}
|
||||
wantValueError bool
|
||||
}{
|
||||
{toParse: `10`, want: json.Number("10"), wantValue: int64(10)},
|
||||
{toParse: `0`, want: json.Number("0"), wantValue: int64(0)},
|
||||
{toParse: `0.12`, want: json.Number("0.12"), wantValue: 0.12},
|
||||
{toParse: `25E-4`, want: json.Number("25E-4"), wantValue: 25E-4},
|
||||
|
||||
{toParse: `"10"`, want: json.Number("10"), wantValue: int64(10)},
|
||||
{toParse: `"0"`, want: json.Number("0"), wantValue: int64(0)},
|
||||
{toParse: `"0.12"`, want: json.Number("0.12"), wantValue: 0.12},
|
||||
{toParse: `"25E-4"`, want: json.Number("25E-4"), wantValue: 25E-4},
|
||||
|
||||
{toParse: `"a""`, wantValueError: true},
|
||||
|
||||
{toParse: `[1]`, wantLexerError: true},
|
||||
{toParse: `{}`, wantLexerError: true},
|
||||
{toParse: `a`, wantLexerError: true},
|
||||
} {
|
||||
l := Lexer{Data: []byte(test.toParse)}
|
||||
|
||||
got := l.JsonNumber()
|
||||
if got != test.want && !test.wantLexerError && !test.wantValueError {
|
||||
t.Errorf("[%d, %q] JsonNumber() = %v; want %v", i, test.toParse, got, test.want)
|
||||
}
|
||||
|
||||
err := l.Error()
|
||||
if err != nil && !test.wantLexerError {
|
||||
t.Errorf("[%d, %q] JsonNumber() lexer error: %v", i, test.toParse, err)
|
||||
} else if err == nil && test.wantLexerError {
|
||||
t.Errorf("[%d, %q] JsonNumber() ok; want lexer error", i, test.toParse)
|
||||
}
|
||||
|
||||
var valueErr error
|
||||
var gotValue interface{}
|
||||
switch test.wantValue.(type) {
|
||||
case float64:
|
||||
gotValue, valueErr = got.Float64()
|
||||
default:
|
||||
gotValue, valueErr = got.Int64()
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(gotValue, test.wantValue) && !test.wantLexerError && !test.wantValueError {
|
||||
t.Errorf("[%d, %q] JsonNumber() = %v; want %v", i, test.toParse, gotValue, test.wantValue)
|
||||
}
|
||||
|
||||
if valueErr != nil && !test.wantValueError {
|
||||
t.Errorf("[%d, %q] JsonNumber() value error: %v", i, test.toParse, err)
|
||||
} else if valueErr == nil && test.wantValueError {
|
||||
t.Errorf("[%d, %q] JsonNumber() ok; want value error", i, test.toParse)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user