diff --git a/reflect.go b/reflect.go index 3280a99..bbe6bfc 100644 --- a/reflect.go +++ b/reflect.go @@ -1032,8 +1032,9 @@ func (r *Reflector) walkProperties(v reflect.Value, parent *Schema, rc *ReflectC } deepIndirect := refl.DeepIndirect(field.Type) + propName := strings.Split(tag, ",")[0] - if tag == "" && field.Anonymous && + if propName == "" && field.Anonymous && (field.Type.Kind() == reflect.Struct || deepIndirect.Kind() == reflect.Struct) { forceReference := (field.Type.Implements(typeOfEmbedReferencer) && field.Tag.Get("refer") == "") || field.Tag.Get("refer") == "true" @@ -1089,7 +1090,6 @@ func (r *Reflector) walkProperties(v reflect.Value, parent *Schema, rc *ReflectC continue } - propName := strings.Split(tag, ",")[0] omitEmpty := strings.Contains(tag, ",omitempty") required := false diff --git a/reflect_test.go b/reflect_test.go index 17d9016..12f107a 100644 --- a/reflect_test.go +++ b/reflect_test.go @@ -1654,7 +1654,15 @@ func TestReflector_Reflect_deeplyEmbedded(t *testing.T) { Baz float64 `json:"baz" title:"Bazzz."` } - s, err := r.Reflect(My{}) + val := My{} + val.DeeplyEmbedded = &DeeplyEmbedded{} + val.Foo = "abcde" + val.Bar = 123 + val.Baz = 4.56 + + assertjson.EqMarshal(t, `{"foo":"abcde","bar":123,"baz":4.56}`, val) + + s, err := r.Reflect(val) require.NoError(t, err) assertjson.EqMarshal(t, `{ @@ -1667,6 +1675,96 @@ func TestReflector_Reflect_deeplyEmbedded(t *testing.T) { }`, s) } +func TestReflector_Reflect_deeplyEmbedded_emptyJSONTags(t *testing.T) { + r := jsonschema.Reflector{} + + type Embed struct { + Foo string `json:",omitempty" minLength:"5"` // Empty name in tag results in Go field name. + Bar int `json:"bar" minimum:"3"` + } + + type DeeplyEmbedded struct { + Embed `json:""` + } + + type My struct { + *DeeplyEmbedded `json:",inline"` // `inline` does not have any specific handling by encoding/json. + + Baz float64 `json:"baz" title:"Bazzz."` + } + + val := My{} + val.DeeplyEmbedded = &DeeplyEmbedded{} + val.Foo = "abcde" + val.Bar = 123 + val.Baz = 4.56 + + assertjson.EqMarshal(t, `{"Foo":"abcde","bar":123,"baz":4.56}`, val) + + s, err := r.Reflect(val) + require.NoError(t, err) + + assertjson.EqMarshal(t, `{ + "properties":{ + "bar":{"minimum":3,"type":"integer"}, + "baz":{"title":"Bazzz.","type":"number"}, + "Foo":{"minLength":5,"type":"string"} + }, + "type":"object" + }`, s) +} + +func TestReflector_Reflect_deeplyEmbedded_validJSONTags(t *testing.T) { + r := jsonschema.Reflector{} + + type Embed struct { + Foo string `json:"foo" minLength:"5"` + Bar int `json:"bar" minimum:"3"` + } + + type DeeplyEmbedded struct { + Embed `json:"emb"` + } + + type My struct { + *DeeplyEmbedded `json:"deep,inline"` // `inline` does not have any specific handling by encoding/json. + + Baz float64 `json:"baz" title:"Bazzz."` + } + + val := My{} + val.DeeplyEmbedded = &DeeplyEmbedded{} + val.Foo = "abcde" + val.Bar = 123 + val.Baz = 4.56 + + assertjson.EqMarshal(t, `{"deep":{"emb":{"foo":"abcde","bar":123}},"baz":4.56}`, val) + + s, err := r.Reflect(val) + require.NoError(t, err) + + assertjson.EqMarshal(t, `{ + "definitions":{ + "JsonschemaGoTestDeeplyEmbedded":{ + "properties":{"emb":{"$ref":"#/definitions/JsonschemaGoTestEmbed"}}, + "type":"object" + }, + "JsonschemaGoTestEmbed":{ + "properties":{ + "bar":{"minimum":3,"type":"integer"}, + "foo":{"minLength":5,"type":"string"} + }, + "type":"object" + } + }, + "properties":{ + "baz":{"title":"Bazzz.","type":"number"}, + "deep":{"$ref":"#/definitions/JsonschemaGoTestDeeplyEmbedded"} + }, + "type":"object" + }`, s) +} + func TestReflector_Reflect_deeplyEmbeddedUnexported(t *testing.T) { r := jsonschema.Reflector{} @@ -1685,7 +1783,14 @@ func TestReflector_Reflect_deeplyEmbeddedUnexported(t *testing.T) { Baz float64 `json:"baz" title:"Bazzz."` } - s, err := r.Reflect(My{}) + val := My{} + val.Foo = "abcde" + val.Bar = 123 + val.Baz = 4.56 + + assertjson.EqMarshal(t, `{"foo":"abcde","bar":123,"baz":4.56}`, val) + + s, err := r.Reflect(val) require.NoError(t, err) assertjson.EqMarshal(t, `{