From b8ea844a25758387d6b2c3fb4d651c5abe9772d2 Mon Sep 17 00:00:00 2001 From: kowloonzh Date: Thu, 2 Dec 2021 20:14:38 +0800 Subject: [PATCH 1/2] feat: support ptr slice --- jsonschema.go | 9 +++++++-- jsonschema_test.go | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/jsonschema.go b/jsonschema.go index 94a4791..b39dbfc 100644 --- a/jsonschema.go +++ b/jsonschema.go @@ -22,6 +22,7 @@ func (d *Document) Read(variable interface{}) { d.setDefaultSchema() value := reflect.ValueOf(variable) + d.read(value.Type(), tagOptions("")) } @@ -62,7 +63,7 @@ func (p *property) read(t reflect.Type, opts tagOptions) { switch kind { case reflect.Slice: - p.readFromSlice(t) + p.readFromSlice(t, opts) case reflect.Map: p.readFromMap(t) case reflect.Struct: @@ -72,13 +73,17 @@ func (p *property) read(t reflect.Type, opts tagOptions) { } } -func (p *property) readFromSlice(t reflect.Type) { +func (p *property) readFromSlice(t reflect.Type, opts tagOptions) { jsType, _, kind := getTypeFromMapping(t.Elem()) + // fmt.Println("readFromSlice", jsType, kind) if kind == reflect.Uint8 { p.Type = "string" } else if jsType != "" { p.Items = &property{} p.Items.read(t.Elem(), tagOptions("")) + } else if kind == reflect.Ptr { + p.Items = &property{} + p.Items.read(t.Elem(), opts) } } diff --git a/jsonschema_test.go b/jsonschema_test.go index 6c70a37..2291784 100644 --- a/jsonschema_test.go +++ b/jsonschema_test.go @@ -94,6 +94,7 @@ type ExampleJSONBasicSlices struct { Slice []string `json:",foo,omitempty"` SliceOfInterface []interface{} `json:",foo"` SliceOfStruct []SliceStruct + SliceOfStructPtr []*SliceStruct } func (self *propertySuite) TestLoadSliceAndContains(c *C) { @@ -124,9 +125,21 @@ func (self *propertySuite) TestLoadSliceAndContains(c *C) { }, }, }, + "SliceOfStructPtr": &property{ + Type: "array", + Items: &property{ + Type: "object", + Required: []string{"Value"}, + Properties: map[string]*property{ + "Value": &property{ + Type: "string", + }, + }, + }, + }, }, - Required: []string{"SliceOfInterface", "SliceOfStruct"}, + Required: []string{"SliceOfInterface", "SliceOfStruct", "SliceOfStructPtr"}, }, }) } From ee3fafbf279b4b7607b95731c0cf1d32c8e0518f Mon Sep 17 00:00:00 2001 From: kowloonzh Date: Mon, 28 Mar 2022 14:54:32 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=A0=91=E7=9A=84?= =?UTF-8?q?=E7=BB=93=E6=9E=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jsonschema.go | 27 ++++++++++++++++++++++++--- jsonschema_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/jsonschema.go b/jsonschema.go index b39dbfc..e5ca170 100644 --- a/jsonschema.go +++ b/jsonschema.go @@ -6,6 +6,7 @@ package jsonschema import ( "encoding/json" + "fmt" "reflect" "strings" ) @@ -43,6 +44,18 @@ func (d *Document) String() string { return string(json) } +func PkgName(t reflect.Type) string { + var pkgName string + if t.Kind() == reflect.Struct { + pkgName = fmt.Sprintf("%s.%s", t.PkgPath(), t.Name()) + } else if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct { + pkgName = fmt.Sprintf("%s.%s", t.Elem().PkgPath(), t.Elem().Name()) + } else if t.Kind() == reflect.Slice { + pkgName = PkgName(t.Elem()) + } + return pkgName +} + type property struct { Type string `json:"type,omitempty"` Format string `json:"format,omitempty"` @@ -75,7 +88,7 @@ func (p *property) read(t reflect.Type, opts tagOptions) { func (p *property) readFromSlice(t reflect.Type, opts tagOptions) { jsType, _, kind := getTypeFromMapping(t.Elem()) - // fmt.Println("readFromSlice", jsType, kind) + if kind == reflect.Uint8 { p.Type = "string" } else if jsType != "" { @@ -103,6 +116,8 @@ func (p *property) readFromStruct(t reflect.Type) { p.Properties = make(map[string]*property, 0) p.AdditionalProperties = false + pkgName := PkgName(t) + count := t.NumField() for i := 0; i < count; i++ { field := t.Field(i) @@ -129,11 +144,17 @@ func (p *property) readFromStruct(t reflect.Type) { } p.Properties[name] = &property{} - p.Properties[name].read(field.Type, opts) - if !opts.Contains("omitempty") { p.Required = append(p.Required, name) } + + // 不支持树状结构的递归 + if PkgName(field.Type) == pkgName { + p.Properties[name].Type = "object" + continue + } + p.Properties[name].read(field.Type, opts) + } } diff --git a/jsonschema_test.go b/jsonschema_test.go index 2291784..ed78aec 100644 --- a/jsonschema_test.go +++ b/jsonschema_test.go @@ -144,6 +144,48 @@ func (self *propertySuite) TestLoadSliceAndContains(c *C) { }) } +type Node struct { + Next *Node +} + +type Tree struct { + Children []*Tree +} + +type ExampleJSONTree struct { + Node Node + Tree Tree +} + +func (self *propertySuite) TestLoadTree(c *C) { + j := &Document{} + j.Read(&ExampleJSONTree{}) + + c.Assert(*j, DeepEquals, Document{ + Schema: "http://json-schema.org/schema#", + property: property{ + Type: "object", + Properties: map[string]*property{ + "Node": &property{ + Type: "object", + Properties: map[string]*property{ + "Next": &property{Type: "object"}, + }, + Required: []string{"Next"}, + }, + "Tree": &property{ + Type: "object", + Properties: map[string]*property{ + "Children": &property{Type: "object"}, + }, + Required: []string{"Children"}, + }, + }, + Required: []string{"Node", "Tree"}, + }, + }) +} + type ExampleJSONNestedStruct struct { Struct struct { Foo string