strangejson最近の進捗はJSONのunmarshal部分の生成ができるようになったこと

github.com

まだ開発中で完成はしていないですが。strangejsonは最近の進捗によりJSONのunmarshal部分の生成ができるようになりました。 これはどういうことかと言うと以下のコードから。

github.com/podhmo/strangejson/examples/pointer02/person.go

package pointer

// Person :
type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`

    Father *Person `json:"father" required:"false"`
    Mother *Person `json:"mother" required:"false"`
}

UnmarshalJSONのメソッドが生成されるようになったということです。この生成されるUnmarshalJSONはrequired,unquiredのチェックを行ってくれます(詳しい内容昔の記事に書いた)。今のところ調べた範囲では任意のJSONにmarshal可能なstructは全部大丈夫だと思います。

ちなみに上のコード例ではわからないですが。外部のパッケージのimportもgoimportsの範囲では見てくれます。そしてちょっといじると元のstructと同じファイルに生成することもできそうです。

package pointer

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

func TestLoad(t *testing.T) {
    {
        var p Person
        err := json.Unmarshal([]byte(`{"name": "foo"}`), &p)
        if err == nil {
            log.Fatal("must error")
        }
        t.Logf("expected: %q", err)
    }
    {
        var p Person
        err := json.Unmarshal([]byte(`{"age": 10}`), &p)
        if err == nil {
            log.Fatal("must error")
        }
        t.Logf("expected: %q", err)
    }
    {
        var p Person
        err := json.Unmarshal([]byte(`{"name": "foo", "age": 10}`), &p)
        if err != nil {
            t.Fatalf("unexpected: %q", err)
        }
    }
    {
        var p Person
        err := json.Unmarshal([]byte(`{"name": "foo", "age": 10, "father": {}}`), &p)
        if err == nil {
            log.Fatal("must error")
        }
        t.Logf("expected: %q", err)
    }
    {
        var p Person
        err := json.Unmarshal([]byte(`{"name": "foo", "age": 10, "father": {"name": "boo", "age": 30}}`), &p)
        if err != nil {
            t.Fatalf("unexpected: %q", err)
        }
    }
}

例えばこういう雑なテストコードが通ります。もうちょっとエラーメッセージは親切にしたいです。

$ go test -v
=== RUN   TestLoad
--- PASS: TestLoad (0.00s)
    pereson_test.go:16: expected: "age is required"
    pereson_test.go:24: expected: "name is required"
    pereson_test.go:39: expected: "name is required"
PASS
ok      github.com/podhmo/strangejson/examples/pointer02    0.004s

実行はこんな感じでやります。

$ strangejson --pkg github.com/podhmo/strangejson/examples/pointer02
2018/02/20 04:58:19 for github.com/podhmo/strangejson/examples/pointer02.Person.UnmarshalJSON
2018/02/20 04:58:19 write /home/nao/go/src/github.com/podhmo/strangejson/examples/pointer02/person_gen.go

生成されたコードは以下の様な感じ。

github.com/podhmo/strangejson/examples/pointer02/person_gen.go

package pointer

import (
    "encoding/json"
    "errors"
)

// UnmarshalJSON : (generated from github.com/podhmo/strangejson/examples/pointer02.Person)
func (x Person) UnmarshalJSON(b []byte) error {
    type internal struct {
        Name   *string  `json:"name"`
        Age    *int     `json:"age"`
        Father **Person `json:"father" required:"false"`
        Mother **Person `json:"mother" required:"false"`
    }

    var p internal
    if err := json.Unmarshal(b, &p); err != nil {
        return err
    }

    if p.Name == nil {
        return errors.New("name is required")
    }
    x.Name = *p.Name
    if p.Age == nil {
        return errors.New("age is required")
    }
    x.Age = *p.Age
    if p.Father != nil {
        x.Father = *p.Father
    }
    if p.Mother != nil {
        x.Mother = *p.Mother
    }

    return nil
}