Code Monkey home page Code Monkey logo

easyjson's People

Contributors

alexej-v avatar boekkooi-fresh avatar bulletmys avatar cafxx avatar cespare avatar doroginin avatar erikdubbelboer avatar ernado avatar gobwas avatar gowebprod avatar irioth avatar kenshaw avatar kirillx avatar levigross avatar loong avatar mxmsk avatar noisyscanner avatar nsd20463 avatar philpearl avatar rvasily avatar sah4ez avatar senseyedeveloper avatar shmel1k avatar skinass avatar stek29 avatar tonnydfg avatar vstarodub avatar xstrom avatar zelenin avatar zikaeroh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

easyjson's Issues

EasyJSON panics on invalid object data

Parsing a string containing a single quote, ", cause EasyJSON to panic:

panic: runtime error: slice bounds out of range

goroutine 1 [running]:
panic(0x1030e0, 0x420206100)
	/var/folders/nz/3m0w2xzd1hq3xnhdfq83pq_00000gn/T/go-fuzz-build368983030/goroot/src/runtime/panic.go:500 +0x1a1
github.com/mailru/easyjson/jlexer.(*Lexer).Consumed(0x420231d78)
	/var/folders/nz/3m0w2xzd1hq3xnhdfq83pq_00000gn/T/go-fuzz-build368983030/gopath/src/github.com/mailru/easyjson/jlexer/lexer.go:538 +0x3a4
github.com/connor4312/easyfuzz.easyjsonF902965fDecodeGithubComConnor4312Easyfuzz(0x420231d78, 0x420231e60)
	/var/folders/nz/3m0w2xzd1hq3xnhdfq83pq_00000gn/T/go-fuzz-build368983030/gopath/src/github.com/connor4312/easyfuzz/fuzz_easyjson.go:115 +0x105b
github.com/connor4312/easyfuzz.(*Foo).UnmarshalJSON(0x420231e60, 0x842026d000, 0x1, 0x200000, 0x420231e90, 0x8)
	/var/folders/nz/3m0w2xzd1hq3xnhdfq83pq_00000gn/T/go-fuzz-build368983030/gopath/src/github.com/connor4312/easyfuzz/fuzz_easyjson.go:233 +0xa6
github.com/connor4312/easyfuzz.Fuzz(0x842026d000, 0x1, 0x200000, 0x0)
	/var/folders/nz/3m0w2xzd1hq3xnhdfq83pq_00000gn/T/go-fuzz-build368983030/gopath/src/github.com/connor4312/easyfuzz/fuzz.go:29 +0x9e
go-fuzz-dep.Main(0x12aed0)
	/var/folders/nz/3m0w2xzd1hq3xnhdfq83pq_00000gn/T/go-fuzz-build368983030/goroot/src/go-fuzz-dep/main.go:49 +0xe8
main.main()
	/var/folders/nz/3m0w2xzd1hq3xnhdfq83pq_00000gn/T/go-fuzz-build368983030/gopath/src/github.com/connor4312/easyfuzz/go.fuzz.main/main.go:10 +0x2d
exit status 2

Test struct:

type Foo struct {
	A         int
	B         float32
	C         string
	PtrA      *int
	PtrB      *float32
	PtrC      *string
	MapStrInt map[string]int
	MapStrAny map[string]interface{}
}

-required by default flag

The same as for omit_empty flag.
I'll make PR if you'll merge it. (you need this feature)
Also added !required tag field
Just answer there.

Struct with no fields leads to the Divide by zero error

if some field of my struct has type "struct{}":

//easyjson:json
type MyStruct struct {
    Text string `json:"text"`
    EmptySlice []struct{} `json:"empty_slice"`
}

it leads to the following error, because count of fields is zero. If I add at least one field to this struct, then I don't have the error anymore:

user$ easyjson ./v1.go
panic: runtime error: integer divide by zero

goroutine 1 [running]:
panic(0x451d800, 0xc42000c0c0)
	/Users/user/.gobrew/versions/1.7.1/src/runtime/panic.go:500 +0x1a1
api/vendor/github.com/mailru/easyjson/gen.(*Generator).genTypeDecoderNoCheck(0xc4201e4780, 0x4848200, 0x44e9bc0, 0xc4202135c8, 0xb, 0x451c08f, 0x7, 0x0, 0x3, 0xc4202135cc, ...)
	/Users/user/go/src/api/vendor/github.com/mailru/easyjson/gen/decoder.go:99 +0x50fc
api/vendor/github.com/mailru/easyjson/gen.(*Generator).genTypeDecoder(0xc4201e4780, 0x4848200, 0x44e9bc0, 0xc4202135c8, 0xb, 0x451c08f, 0x7, 0x0, 0x3, 0x0, ...)
	/Users/user/go/src/api/vendor/github.com/mailru/easyjson/gen/decoder.go:68 +0x52c
api/vendor/github.com/mailru/easyjson/gen.(*Generator).genStructFieldDecoder(0xc4201e4780, 0x4848200, 0x456e180, 0x451c080, 0x7, 0x0, 0x0, 0x4848200, 0x44e9bc0, 0x451c089, ...)
	/Users/user/go/src/api/vendor/github.com/mailru/easyjson/gen/decoder.go:238 +0x27c
api/vendor/github.com/mailru/easyjson/gen.(*Generator).genStructDecoder(0xc4201e4780, 0x4848200, 0x456e180, 0x44f2360, 0xc4201b7e70)
	/Users/user/go/src/api/vendor/github.com/mailru/easyjson/gen/decoder.go:409 +0x131b
api/vendor/github.com/mailru/easyjson/gen.(*Generator).genDecoder(0xc4201e4780, 0x4848200, 0x456e180, 0xc420213e87, 0x0)
	/Users/user/go/src/api/vendor/github.com/mailru/easyjson/gen/decoder.go:333 +0xb3
api/vendor/github.com/mailru/easyjson/gen.(*Generator).Run(0xc4201e4780, 0x483daa0, 0xc42002c010, 0x0, 0x0)
	/Users/user/go/src/api/vendor/github.com/mailru/easyjson/gen/generator.go:182 +0x12e
main.main()
	/Users/user/go/src/api/api/handler/easyjson-bootstrap223403038.go:21 +0xd2
exit status 2
Bootstrap failed: exit status 1

In this situation I want to use empty struct to have just a fake empty slice to follow the api contract, but inside this struct I never need to pass any data, it just helps mobile apps to parse my response to the same structure we use in other handlers.

Please fix it. Thanks!

Required/Optional fields

For example we have such struct:

type SomeStruct struct {
    Key1 string
    Key2 string
    Key3 *string

where key3 is nullable, because zero-value is valid value for it.
And all these examples can be successfully unmarshalled:

{
    "key1": "value1",
    "key2": "value2",
    "key3": "value3"
}
{
    "key1": "value1",
    "key2": "value2",
        "key3": ""
}
{
    "key1": "value1",
    "key2": "value2",
}

But if key1 or key2 is missed then unmarshall must return an error.

What do you think about such mode?

EasyJSON disregards invalid input if a string prefix is valid

Discovered this quickly when throwing go-fuzz to detect behavioural differences between encoding/json and EasyJSON. EasyJSON seems to accept and stop parting if a prefix of a string is valid input. For example, all of the below lines are seen to be "valid" JSON strings:

null 4
{}{
null]

encoding/json returns an error when trying to parse these, EasyJSON accepts them

(Un)Marshal string to []byte

Is there any possibilities to unmarshal json-string to []byte and vice versa? Am I right that currently no?
It can be useful to reduce memory allocations and avoid unnecessary sting <-> []byte converting in application.

Anyway, I have a dummy fix for that and can formalize it in PR.

But the question is in what way to tell parser to process []byte that way. With cli falg e.g. -stringtobytes or better with tag e.g. easyjson:"string" for desired fields:

type T struct {
    name []byte `easyjson:"string"`
    ...
}

What do you think?

encoding/json accepts case-insensitive keys, while easyjson doesn't

t2.go:

package t2

type S struct {
    A int
}

t2_test.go:

package t2

import (
    "encoding/json"
    "strings"
    "testing"
)

func TestCaseInsensitiveDecoding(t *testing.T) {
    d := json.NewDecoder(strings.NewReader(`{"a":1}`))
    var s S
    err := d.Decode(&s)
    if err != nil {
        t.Fatal(err)
    }
    if s.A != 1 {
        t.Fatal("expected 1, got", s.A)
    }
}

Without easyjson-generated code the test is passed; with it it fails:

t2_test.go:17: expected 1, got 0

This behaviour should be either documented or fixed.

Marshal methods are not generated for type aliases

Currently, it appears that type aliases are ignored when generating the marshaler methods. For instance,
on:

type Test struct {
    A string
}

type TestAlias Test

the file generated by easyjson -all does not contain any methods for TestAlias at all. This means that anything of type TestAlias is not an easyjson.Marshaler without an explicit cast.

undefined: net in net.IP

Building after running easyjson on the struct below fails with an error undefined: net in net.IP (because net doesn't get added to imports).

type S struct {
    Time       time.Time
    Client struct {
        IP   net.IP
        Mask uint8
    }
}

Lexer rewrites invalid token error on unmarshall

Unmarshall does not return correct error on invalid token type.
This is caused by call to lexer.Consumed which overwrites previous error.

Example struct:

type Model struct {
	A int    `json:"a"`
	B string `json:"b"`
}

Input:
{"a": "1", "b": "text"}

Got error:
parse error: invalid character ',' after top-level value near offset 9 of ', "b": "text"}'

Expected:
parse error: expected number near offset 9 of '1'

Dynamically marshalling specific fields

Basically I am also looking for pquerna/ffjson#150 (in some json library).

Wondering if you had ideas as to if/how you'd like to see support for it. I was thinking about adding an unexported function field to structs that need this support, and adding a conditional call to that function to the generated code.

type Selectable struct {
    A string
    B string
    easyjsonSelectField func(string) bool
}

s := Selectable{}
s.easyjsonSelectField = func(field string) bool {
    return true
}

This could be in addition to, or overriding omitempty.
I don't like that this requires modifying the struct, but I couldn't easily think of a better way to provide support to dynamically manage such a thing from generated code.

Happy to hear if you have any opinions on this functionality in general, or implementation.

easyjson doesn't respect TextUnmarshaler

https://golang.org/src/encoding/encoding.go?s=1851:1919#L36

For example, the following code will not work as expected with easyjson:

package main

import (
    "encoding/json"
    "fmt"
)

type Number int64

func (n *Number) UnmarshalText(text []byte) error {
    switch string(text) {
    case "ONE":
        *n = 1
    case "TWO":
        *n = 2
    default:
        *n = -1
    }
    return nil
}

type S struct {
    Index Number
}

func main() {
    var s S
    json.Unmarshal([]byte(`{"index": "ONE"}`), &s)
    fmt.Println(s)
}

jlexer: Lexer.Delim allocate two memory

Hi, Thank you for creating easyjson, it's so fast.
But when I profiling the generated code, I found Lexer.Delim() call r.errInvalidToken convert byte to slice of byte and then covert it to string.

I just modify Lexer, add errInvalidToken2(expected byte) just be used for Delim.

Package is a program, not an importable package

Fails when running against this file...

I've created package foo, and have the following file main.go

package main

import (
    "fmt"
)

type Foo struct {
    Name string
}

func main() {
    f := Foo{Name: "Bar"}
    fmt.Printf("%+v\n", f)
}

Output

$ easyjson -all main.go 
/var/folders/wj/ggsd2sgs2b1_vnplhkcv6g0jk5xz5m/T/easyjson715726581.go:8:3: import "github.com/scottjbarr/foo" is a program, not an importable package
Bootstrap failed: exit status 1

A file called main_easyjson.go with the following content is created

package  main

import (
  "github.com/mailru/easyjson/jwriter"
  "github.com/mailru/easyjson/jlexer"
)
func (* Foo ) MarshalJSON() ([]byte, error) { return nil, nil }
func (* Foo ) UnmarshalJSON([]byte) error { return nil }
func (* Foo ) MarshalEasyJSON(w *jwriter.Writer) {}
func (* Foo ) UnmarshalEasyJSON(l *jlexer.Lexer) {}
  • Also, the output file is not gofmt'ed.

Unsafe in lexer.go

Hi all,

I'm working on an appengine application and one of my dependencies recently added an import to easyjson/jlexer. The problem is that https://github.com/mailru/easyjson/blob/master/jlexer/lexer.go#L207 is importing unsafe and deploying to appengine fails for code with unsafe.

Now, I understand that this is done to prevent copying the string bytes, but is there any way to rewrite it without unsafe? It would help all of us who write appengine apps.

Thanks,
tk

go get fails on x32 systems

go get -u github.com/mailru/easyjson/...
# github.com/mailru/easyjson/benchmark
/opt/go/gopath/src/github.com/mailru/easyjson/benchmark/data_var.go:7: constant 250126199840518145 overflows int
/opt/go/gopath/src/github.com/mailru/easyjson/benchmark/data_var.go:12: constant 24012619984051000 overflows int
# github.com/mailru/easyjson/tests
/opt/go/gopath/src/github.com/mailru/easyjson/tests/data.go:91: constant 4294967295 overflows int
/opt/go/gopath/src/github.com/mailru/easyjson/tests/data.go:94: constant 4294967295 overflows int
/opt/go/gopath/src/github.com/mailru/easyjson/tests/data.go:103: constant 4294967295 overflows int
/opt/go/gopath/src/github.com/mailru/easyjson/tests/data.go:106: constant 4294967295 overflows int
/opt/go/gopath/src/github.com/mailru/easyjson/tests/data.go:194: constant 4294967295 overflows int
/opt/go/gopath/src/github.com/mailru/easyjson/tests/data.go:197: constant 4294967295 overflows int

easyjson is not so vendor friendly

Consider the following code:

import "github.com/repo1/package2"

//easyjson:json
type Gen1 struct {
  A package2.Type1 `json:"a"`
}

Given that github.com/repo1/package2 is already vendored, e.g. there is a vendor/github.com/repo1/package2 directory along with the go source code above. Running the easyjson binary will create an import line that looks somelike:

import package2 "github.com/foo/bar/vendor/github.com/repo1/package2"

Instead, it should just be:

import package2 "github.com/repo1/package2"

My go env just FYI:

GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/stevejiang/developments/go"
GORACE=""
GOROOT="/usr/local/Cellar/go/1.6.2/libexec"
GOTOOLDIR="/usr/local/Cellar/go/1.6.2/libexec/pkg/tool/darwin_amd64"
GO15VENDOREXPERIMENT="1"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fno-common"
CXX="clang++"
CGO_ENABLED="1"

Unmarshal to array of struct

Hi,

Given a struct Test, that has marshal and unmarshal interfaces generated, is it possible to unmarshal data to []Test?

I have tried various alternatives like:

var ArrTestType []Test

type ArrTest struct {
    ArrTestType //anonymous embedded field
}

but it doesnt work. In this case, easyjson complains that it expects a struct (for the embedded field).

Fails to property generate if import has a .

if your import has a dependency with a "." in it such as
import "gopkg.in/inf.v0"
This will fail to generate the easyjson file properly. It will treat the package as inf.v0 instead of as inf

Fails to generate code for maps within structs

Attempting to run easyjson on this file generates the following errors:

types.go

package types

type UUID string
type Meter string

type Thing struct {
  UUID   UUID
  Length Meter
}

type Response struct {
  Things map[UUID]Thing
}

errors:

# ezjson_test
./types_easyjson.go:27: undefined: types in types.UUID
./types_easyjson.go:27: undefined: types in types.Thing
./types_easyjson.go:36: cannot use key (type string) as type UUID in map index
./types_easyjson.go:63: cannot use v2_name (type UUID) as type string in argument to out.String

time.Time does not marshall correctly

Marshalling and unmarshalling a struct like this leaves MyTime set to nil

type T struct {
MyTime time.Time json:"my_time"
}

encoding/json supports this

support non empty interface

easyjson doesn't support non empty interface members during marshal/unmarshal operations where as standard Go encoding/json does.

Cannot use X (type Y) as type Z errors when compiling code with structs having custom types

Sorry for confusing title, but the problem is follows. I have a struct that looks like this:

type Message struct {
    UID       MessageID        `json:"uid"`
    Timestamp string           `json:"timestamp"`
    Info      *ClientInfo      `json:"info,omitempty"`
    Channel   Channel          `json:"channel"`
    Data      *json.RawMessage `json:"data"`
    Client    ConnID           `json:"client,omitempty"`
}

After generating *_easyjson.go file I tried to build my source code but got errors:

./message_easyjson.go:23: cannot use in.String() (type string) as type MessageID in assignment
./message_easyjson.go:35: cannot use in.String() (type string) as type Channel in assignment
./message_easyjson.go:47: cannot use in.String() (type string) as type ConnID in assignment
./message_easyjson.go:62: cannot use in.UID (type MessageID) as type string in argument to out.String
./message_easyjson.go:80: cannot use in.Channel (type Channel) as type string in argument to out.String
./message_easyjson.go:93: cannot use in.Client (type ConnID) as type string in argument to out.String
./message_easyjson.go:125: cannot use in.String() (type string) as type UserID in assignment
./message_easyjson.go:127: cannot use in.String() (type string) as type ConnID in assignment
./message_easyjson.go:162: cannot use in.User (type UserID) as type string in argument to out.String
./message_easyjson.go:166: cannot use in.Client (type ConnID) as type string in argument to out.String

Generated code - https://gist.github.com/FZambia/080a25f58ce81c510533

In my case types defined in this way:

type (
    Channel string
    ChannelID string
    UserID string
    ConnID string
    MessageID string
)

And ClientInfo is

type ClientInfo struct {
    User        UserID           `json:"user"`
    Client      ConnID           `json:"client"`
    DefaultInfo *json.RawMessage `json:"default_info,omitempty"`
    ChannelInfo *json.RawMessage `json:"channel_info,omitempty"`
}

How this can be fixed?

Invalid cross-device link

I'm not sure if I'm doing something wrong.

Here's the model file:

package models

// User is a person with an account. We only need to know their uid,
// email and location. Location can be USA or NON-USA
//easyjson:json
type User struct {
    UID      string `json:"uid" gorethink:"id"`
    Email    string `json:"email" gorethink:"email"`
    Location string `json:"location" gorethink:"location"`
    Services map[string]struct {
        Enabled bool   `json:"enabled,omitempty" gorethink:"enabled"`
        Status  string `json:"status,omitempty" gorethink:"status"`
    } `json:"services,omitempty" gorethink:"services,omitempty"`
}

Here's the output of the command:

msuppo@faster:~/Work/golang/src/github.com/matteosuppo/ctc-users$ easyjson -all api/models/user.go 
Bootstrap failed: rename /tmp/easyjson-out787644588 api/models/user_easyjson.go: invalid cross-device link

And here's the file generated

package  models

import (
  "github.com/mailru/easyjson/jwriter"
  "github.com/mailru/easyjson/jlexer"
)
func (* User ) MarshalJSON() ([]byte, error) { return nil, nil }
func (* User ) UnmarshalJSON([]byte) error { return nil }
func (* User ) MarshalEasyJSON(w *jwriter.Writer) {}
func (* User ) UnmarshalEasyJSON(l *jlexer.Lexer) {}

file X is not in GOPATH error when GOPATH ends with `/`

Hello, here is a problem I came across when trying easyjson โ€“ when I run easyjson.go myfile.go I get an error from title.

After investigating a bit I found the reason: my GOPATH ends with / so it does not pass a check in this line.

The easiest fix I can imagine is sth like:

import "path/filepath"
...
prefix := filepath.Join(p, "src") + "/"

But maybe there is a cleaner way to do it.

Give an explicit error message for nested maps with unsupported key type

When trying to apply easyjson to nested maps like map[string]map[uint32]string, it produces invalid code:

        for v2_name, v2_value := range in.Field {
            if !v2_first {
                out.RawByte(',')
            }
            v2_first = false
            out.String(string(v2_name))
            out.RawByte(':')
        }

which gives this error:

v2_value declared and not used

It would be nice to have an explicit error message, like we get with non-nested maps:

map type uint32 not supported: only string keys are allowed

Support for unexported structs

I continue my experiments with easyjson and results look really impressive at moment.

The problem I came across while adopting easyjson to Centrifugo is that it does not support code generation for unexported structs - i.e. I get lots of errors like cannot refer to unexported name libcentrifugo.apiCommand when run easyjson -all commands.go for this file. I can make all structs exported in the end of course but hope there is a simple way to support them too by easyjson.

Configurable Marshalling

Hi, not sure if you would think it's useful/good and would want a PR, but I added a feature to easy-json to allow some manipulation of the Marshaller at runtime.

Use case is that it's not uncommon to have a large struct and sometimes wanting to (dynamically) exclude some fields from marshaling (to send json subset of struct to endpoints)

See here,
tcolar#1

Embedded structs

Hi,

I have embedded structs and I get this problem "eaysjson_decode_... redeclared in this block ... previous declaration at ..."
I've noticed that structs are also copied where they were embedded. Do you have any options to turn this off?
Btw.: I tried to run easyjson file by file, and for the whole directory too, but I've got the same problem.

Parse error when parsing a degenerated case of JSON

t1.go:

package t1

type S struct{}

t1_test.go:

package t1

import (
    "encoding/json"
    "strings"
    "testing"
)

func TestDecodingNull(t *testing.T) {
    d := json.NewDecoder(strings.NewReader("null"))
    err := d.Decode(&S{})
    if err != nil {
        t.Fatal(err)
    }
}

Without easyjson-generated code the test is passed; with it it fails:

t1_test.go:13: parse error: expected {, got '' at byte 0.

null is a valid JSON.

Unmarshalling not as fast as expected?

Comparing easyjson to encoding/json, I am not seeing much speed improvements.

I am using easyjson.UnmarshalFromReader to Unmarshall ~2000 objects per second and am noticing an average of 380ms per 2k objects. Using the same test on the same data, I am seeing an average of 420ms per 2k objects with encoding/json.

Are there some optimisation possibilities that I am missing or is this expected behavior?

Failure in unmarshal surrogate unicode encoding (utf16) - BUG

Hi ,

Example JSON File is :

{
  "name":"Khashayar is not \ud83d\ude08"
}

And go model is :

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

Unmarshal test instance on mentioned JSON file will fail with this error:
parse error: invalid character 'K' after top-level value near offset 12 of 'Khashayar is not \ud83d\ude08"
}

as it's obvious json file is valid and represent :

{"name":"Khashayar is not ๐Ÿ˜ˆ"}

the problem is from processEscape in lexer.go .
i will send pull request soon .

Embedded reference struct should not need to be "new"'ed unless there are corresponding fields

Consider the following JSON:

{
  "Direct1":1,
  "Embedded2": 2,
  "Embedded3": 3
}

And given the following structs:

type A struct {
  Direct1 int
  *B
}

type B struct {
  Embedded2 int,
  Embedded3 int
}

When one generate the custom unmarshaling, there will be a line in the implementation that would read something like:

out.B = new(B)

regardless of if he has those embedded fields in the raw JSON string; e.g. when the JSON looks like:

{"Direct1":1}

he will still end up creating a new B. I think this B type shouldn't be created in this case because 1) it would waste additional memory, 2) it would make marshaling back into a different object when the string was directly marshaled from an A without B.

Stable version branches

We would like to be able to refer to a stable branch in order to avoid pulling in the current state of master for builds.

Lexer emits EOF on nil slices

Documentation states that all parsing errors should be LexerErrors, but it's possible for this not to be the case. This resulted in an error incorrectly being flagged as an internal error, when actually the client had simply omitted a field to be parsed.

Nothing is generated for maps not in structs

Hi

I tried to generate un-/marshalers for the following code:

package gen

type Item struct {
    Val int
}

type TStruct struct {
    Mp map[string] Item
}

type TMap map[string] Item

The code was generated for TStruct and Item only, but map TMap was ignored. I modified genDecoder and genEncoder a the way like:

func (g *Generator) genDecoder(t reflect.Type) error {
    switch t.Kind() {
    case reflect.Map:
        return g.genMapDecoder(t)
    case reflect.Slice, reflect.Array:
        return g.genSliceArrayDecoder(t)
    default:
        return g.genStructDecoder(t)
    }
}

where genMapDecoder is similar to genSliceArrayDecoder except the Kind check. And it works!

So, I wonder why the current version doesn't allow to generate code for maps which not consisted in any struct?

Inline struct fields are omitted in case of name collision

Consider following code:

type Outer struct {
    Inner
    A int64       `json:"a"`
    B interface{} `json:"b"`
}

type Inner struct {
    A map[string]float64 `json:"innerA"`
    B string             `json:"innerB"`
}

Serializing Outer{} using encoding/json gives us {"innerA":null,"innerB":"","a":0,"b":null} (snippet), but if we try to do the same in easyjson fields of inner struct are supressed by fields of the outer struct.

Relatively loose json type, numeric and string are compatible with each other

Migration from other languages to golang, can much some weakly typed languages even the Java string and numerical mutual compatibility and conversion, lead to the client without a fully the same json type, add a function in the generated code optional loose type model, used for compatibility problems left over by history

Invalid code generated for slices of struct pointers

Easyjson adds unneeded and invalid package name to types when dealing with slices of struct pointers ([]*MyStruct).

Minimal example:

package issue

type S struct {
    B string
}

type Exp struct {
    A []*S
}

Relevant generated code:

func easyjson_decode_github_com_mailru_easyjson_issue_Exp(in *jlexer.Lexer, out *Exp) {
    in.Delim('{')
    for !in.IsDelim('}') {
        key := in.UnsafeString()
        in.WantColon()
        if in.IsNull() {
            in.Skip()
            in.WantComma()
            continue
        }
        switch key {
        case "A":
            in.Delim('[')
            if !in.IsDelim(']') {
                out.A = make([]*issue.S, 0, 8)
            } else {
                out.A = nil
            }
            for !in.IsDelim(']') {
                var v1 *issue.S
                if in.IsNull() {
                    in.Skip()
                    v1 = nil
                } else {
                    v1 = new(S)
                    (*v1).UnmarshalEasyJSON(in)
                }
                out.A = append(out.A, v1)
                in.WantComma()
            }
            in.Delim(']')
        default:
            in.SkipRecursive()
        }
        in.WantComma()
    }
    in.Delim('}')
}

Invalid code (issue is not imported and can't be since it would produce import cycle):

out.A = make([]*issue.S, 0, 8)

Unrecognized package name error

Given a foo package containing at least two files and a map[string][]stuct member:

bar.go :

package foo

//easyjson:json
type Bar struct {
    Name  string
    Bozes map[string][]Boz
}

and boz.go :

package foo

//easyjson:json
type Boz struct {
    Name string
}

Then:

~/go/src/github.com/jeromenerf/foo % easyjson bar.go boz.go
# github.com/jeromenerf/foo
./bar_easyjson.go:36: undefined: foo in foo.Boz
./bar_easyjson.go:43: undefined: foo in foo.Boz
Bootstrap failed: exit status 2

(Running easyjson bar.go boz.go doesn't produce any error however).

The files produced :

// AUTOGENERATED FILE: easyjson marshaller/unmarshallers.

package foo

import (
    json "encoding/json"
    jlexer "github.com/mailru/easyjson/jlexer"
    jwriter "github.com/mailru/easyjson/jwriter"
)

var _ = json.RawMessage{} // suppress unused package warning

func easyjson_4347b5c1_decode_github_com_jeromenerf_foo_Bar(in *jlexer.Lexer, out *Bar) {
    if in.IsNull() {
        in.Skip()
        return
    }
    in.Delim('{')
    for !in.IsDelim('}') {
        key := in.UnsafeString()
        in.WantColon()
        if in.IsNull() {
            in.Skip()
            in.WantComma()
            continue
        }
        switch key {
        case "Name":
            out.Name = string(in.String())
        case "Bozes":
            if in.IsNull() {
                in.Skip()
            } else {
                in.Delim('{')
                if !in.IsDelim('}') {
                    out.Bozes = make(map[string][]foo.Boz)
                } else {
                    out.Bozes = nil
                }
                for !in.IsDelim('}') {
                    key := string(in.String())
                    in.WantColon()
                    var v1 []foo.Boz
                    in.Delim('[')
                    if !in.IsDelim(']') {
                        v1 = make([]Boz, 0, 4)
                    } else {
                        v1 = nil
                    }
                    for !in.IsDelim(']') {
                        var v2 Boz
                        (v2).UnmarshalEasyJSON(in)
                        v1 = append(v1, v2)
                        in.WantComma()
                    }
                    in.Delim(']')
                    (out.Bozes)[key] = v1
                    in.WantComma()
                }
                in.Delim('}')
            }
        default:
            in.SkipRecursive()
        }
        in.WantComma()
    }
    in.Delim('}')
}
func easyjson_4347b5c1_encode_github_com_jeromenerf_foo_Bar(out *jwriter.Writer, in Bar) {
    out.RawByte('{')
    first := true
    _ = first
    if !first {
        out.RawByte(',')
    }
    first = false
    out.RawString("\"Name\":")
    out.String(string(in.Name))
    if !first {
        out.RawByte(',')
    }
    first = false
    out.RawString("\"Bozes\":")
    if in.Bozes == nil {
        out.RawString(`null`)
    } else {
        out.RawByte('{')
        v3_first := true
        for v3_name, v3_value := range in.Bozes {
            if !v3_first {
                out.RawByte(',')
            }
            v3_first = false
            out.String(string(v3_name))
            out.RawByte(':')
            out.RawByte('[')
            for v4, v5 := range v3_value {
                if v4 > 0 {
                    out.RawByte(',')
                }
                (v5).MarshalEasyJSON(out)
            }
            out.RawByte(']')
        }
        out.RawByte('}')
    }
    out.RawByte('}')
}
func (v Bar) MarshalJSON() ([]byte, error) {
    w := jwriter.Writer{}
    easyjson_4347b5c1_encode_github_com_jeromenerf_foo_Bar(&w, v)
    return w.Buffer.BuildBytes(), w.Error
}
func (v Bar) MarshalEasyJSON(w *jwriter.Writer) {
    easyjson_4347b5c1_encode_github_com_jeromenerf_foo_Bar(w, v)
}
func (v *Bar) UnmarshalJSON(data []byte) error {
    r := jlexer.Lexer{Data: data}
    easyjson_4347b5c1_decode_github_com_jeromenerf_foo_Bar(&r, v)
    return r.Error()
}
func (v *Bar) UnmarshalEasyJSON(l *jlexer.Lexer) {
    easyjson_4347b5c1_decode_github_com_jeromenerf_foo_Bar(l, v)
}

and

// TEMPORARY AUTOGENERATED FILE: easyjson stub code to make the package
// compilable during generation.

package  foo

import (
  "github.com/mailru/easyjson/jwriter"
  "github.com/mailru/easyjson/jlexer"
)

func (* Boz ) MarshalJSON() ([]byte, error) { return nil, nil }
func (* Boz ) UnmarshalJSON([]byte) error { return nil }
func (* Boz ) MarshalEasyJSON(w *jwriter.Writer) {}
func (* Boz ) UnmarshalEasyJSON(l *jlexer.Lexer) {}

type EasyJSON_exporter_Boz *Boz

Wrong behaviour for embedded type

Hi

type Parent struct {
  ParentMember string
  Child
}

type Child struct {
  ChildMember string
}
  1. If Child has an easyjson implementation.
  2. Then attempt to marshal Parent.
  3. Then ParentMember is not present in output! (unexpected)

It's caused by parent inheriting child's implementation of json.Marhsaller interface.

I don't know if there's any possible solution. I hope there is. But maybe in README.MD should add a note saying "any type that embeds a type using easyjson must itself also use easyjson".

fails to correctly encode non-pointer structures.

package main

import (
    "encoding/json"
    "fmt"
)

//go:generate easyjson -snake_case example.go

//easyjson:json
type obj struct {
    Field1 string
    Field2 string
}

func main() {
    var (
        buffer []byte
        err    error
    )
    details := obj{
        Field1: "foo",
        Field2: "bar",
    }

    if buffer, err = json.Marshal(details); err != nil {
        fmt.Println("marshal error", err)
        return
    }

    fmt.Println("bad", string(buffer))

    if buffer, err = json.Marshal(&details); err != nil {
        fmt.Println("marshal error", err)
        return
    }

    fmt.Println("good", string(buffer))
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.