diff --git a/reflect.go b/reflect.go index 2714d1f..4bf90a3 100644 --- a/reflect.go +++ b/reflect.go @@ -129,24 +129,13 @@ func checkSchemaSetup(params InterceptSchemaParams) (bool, error) { v := params.Value s := params.Schema - vi := v.Interface() - if v.Kind() == reflect.Ptr && v.IsNil() { - vi = reflect.New(v.Type().Elem()).Interface() - } - - vpi := reflect.New(v.Type()).Interface() - - reflectEnum(s, "", vi) + reflectEnum(s, "", v.Interface()) var e Exposer - if exposer, ok := vi.(Exposer); ok { - e = exposer - } - - if exposer, ok := vi.(Exposer); ok { + if exposer, ok := safeInterface(v).(Exposer); ok { e = exposer - } else if exposer, ok := vpi.(Exposer); ok { + } else if exposer, ok := ptrTo(v).(Exposer); ok { e = exposer } @@ -164,9 +153,9 @@ func checkSchemaSetup(params InterceptSchemaParams) (bool, error) { var re RawExposer // Checking if RawExposer is defined on a current value. - if exposer, ok := vi.(RawExposer); ok { + if exposer, ok := safeInterface(v).(RawExposer); ok { re = exposer - } else if exposer, ok := vpi.(RawExposer); ok { // Checking if RawExposer is defined on a pointer to current value. + } else if exposer, ok := ptrTo(v).(RawExposer); ok { // Checking if RawExposer is defined on a pointer to current value. re = exposer } @@ -176,11 +165,15 @@ func checkSchemaSetup(params InterceptSchemaParams) (bool, error) { return true, err } - err = json.Unmarshal(schemaBytes, s) + var rs Schema + + err = json.Unmarshal(schemaBytes, &rs) if err != nil { return true, err } + *s = rs + return true, nil } @@ -389,6 +382,8 @@ func (r *Reflector) reflectDefer(defName string, typeString refl.TypeString, rc func (r *Reflector) checkTitle(v reflect.Value, s *Struct, schema *Schema) { if vd, ok := safeInterface(v).(Described); ok { schema.WithDescription(vd.Description()) + } else if vd, ok := ptrTo(v).(Described); ok { + schema.WithDescription(vd.Description()) } if s != nil && s.Description != nil { @@ -397,6 +392,8 @@ func (r *Reflector) checkTitle(v reflect.Value, s *Struct, schema *Schema) { if vt, ok := safeInterface(v).(Titled); ok { schema.WithTitle(vt.Title()) + } else if vt, ok := ptrTo(v).(Titled); ok { + schema.WithTitle(vt.Title()) } if s != nil && s.Title != nil { @@ -535,6 +532,10 @@ func (r *Reflector) reflect(i interface{}, rc *ReflectContext, keepType bool, pa if preparer, ok := safeInterface(v).(Preparer); ok { err := preparer.PrepareJSONSchema(sp) + return schema, err + } else if preparer, ok := ptrTo(v).(Preparer); ok { + err := preparer.PrepareJSONSchema(sp) + return schema, err } @@ -556,25 +557,48 @@ func checkTextMarshaler(t reflect.Type, schema *Schema) bool { } func safeInterface(v reflect.Value) interface{} { + if !v.IsValid() { + return nil + } + if v.Kind() == reflect.Ptr && !v.Elem().IsValid() { - v = reflect.New(v.Type()) + v = reflect.New(v.Type().Elem()) } return v.Interface() } +func ptrTo(v reflect.Value) interface{} { + if !v.IsValid() { + return nil + } + + rd := reflect.New(v.Type()) + rd.Elem().Set(v) + + return rd.Interface() +} + func (r *Reflector) applySubSchemas(v reflect.Value, rc *ReflectContext, schema *Schema) error { vi := safeInterface(v) + vp := ptrTo(v) + var oe OneOfExposer if e, ok := vi.(OneOfExposer); ok { + oe = e + } else if e, ok := vp.(OneOfExposer); ok { + oe = e + } + + if oe != nil { var schemas []SchemaOrBool - for _, item := range e.JSONSchemaOneOf() { + for _, item := range oe.JSONSchemaOneOf() { rc.Path = append(rc.Path, "oneOf") s, err := r.reflect(item, rc, false, schema) if err != nil { - return fmt.Errorf("failed to reflect 'oneOf' values of %T: %w", vi, err) + return fmt.Errorf("failed to reflect 'oneOf' values of %T: %w", oe, err) } schemas = append(schemas, s.ToSchemaOrBool()) @@ -583,15 +607,22 @@ func (r *Reflector) applySubSchemas(v reflect.Value, rc *ReflectContext, schema schema.OneOf = schemas } + var ane AnyOfExposer if e, ok := vi.(AnyOfExposer); ok { + ane = e + } else if e, ok := vp.(AnyOfExposer); ok { + ane = e + } + + if ane != nil { var schemas []SchemaOrBool - for _, item := range e.JSONSchemaAnyOf() { + for _, item := range ane.JSONSchemaAnyOf() { rc.Path = append(rc.Path, "anyOf") s, err := r.reflect(item, rc, false, schema) if err != nil { - return fmt.Errorf("failed to reflect 'anyOf' values of %T: %w", vi, err) + return fmt.Errorf("failed to reflect 'anyOf' values of %T: %w", ane, err) } schemas = append(schemas, s.ToSchemaOrBool()) @@ -600,15 +631,22 @@ func (r *Reflector) applySubSchemas(v reflect.Value, rc *ReflectContext, schema schema.AnyOf = schemas } + var ale AllOfExposer if e, ok := vi.(AllOfExposer); ok { + ale = e + } else if e, ok := vp.(AllOfExposer); ok { + ale = e + } + + if ale != nil { var schemas []SchemaOrBool - for _, item := range e.JSONSchemaAllOf() { + for _, item := range ale.JSONSchemaAllOf() { rc.Path = append(rc.Path, "allOf") s, err := r.reflect(item, rc, false, schema) if err != nil { - return fmt.Errorf("failed to reflect 'allOf' values of %T: %w", vi, err) + return fmt.Errorf("failed to reflect 'allOf' values of %T: %w", ale, err) } schemas = append(schemas, s.ToSchemaOrBool()) @@ -617,45 +655,73 @@ func (r *Reflector) applySubSchemas(v reflect.Value, rc *ReflectContext, schema schema.AllOf = schemas } + var ne NotExposer if e, ok := vi.(NotExposer); ok { + ne = e + } else if e, ok := vp.(NotExposer); ok { + ne = e + } + + if ne != nil { rc.Path = append(rc.Path, "not") - s, err := r.reflect(e.JSONSchemaNot(), rc, false, schema) + s, err := r.reflect(ne.JSONSchemaNot(), rc, false, schema) if err != nil { - return fmt.Errorf("failed to reflect 'not' value of %T: %w", vi, err) + return fmt.Errorf("failed to reflect 'not' value of %T: %w", ne, err) } schema.WithNot(s.ToSchemaOrBool()) } + var ie IfExposer if e, ok := vi.(IfExposer); ok { + ie = e + } else if e, ok := vp.(IfExposer); ok { + ie = e + } + + if ie != nil { rc.Path = append(rc.Path, "if") - s, err := r.reflect(e.JSONSchemaIf(), rc, false, schema) + s, err := r.reflect(ie.JSONSchemaIf(), rc, false, schema) if err != nil { - return fmt.Errorf("failed to reflect 'if' value of %T: %w", vi, err) + return fmt.Errorf("failed to reflect 'if' value of %T: %w", ie, err) } schema.WithIf(s.ToSchemaOrBool()) } + var te ThenExposer if e, ok := vi.(ThenExposer); ok { + te = e + } else if e, ok := vp.(ThenExposer); ok { + te = e + } + + if te != nil { rc.Path = append(rc.Path, "if") - s, err := r.reflect(e.JSONSchemaThen(), rc, false, schema) + s, err := r.reflect(te.JSONSchemaThen(), rc, false, schema) if err != nil { - return fmt.Errorf("failed to reflect 'then' value of %T: %w", vi, err) + return fmt.Errorf("failed to reflect 'then' value of %T: %w", te, err) } schema.WithThen(s.ToSchemaOrBool()) } + var ee ElseExposer if e, ok := vi.(ElseExposer); ok { + ee = e + } else if e, ok := vp.(ElseExposer); ok { + ee = e + } + + if ee != nil { rc.Path = append(rc.Path, "if") - s, err := r.reflect(e.JSONSchemaElse(), rc, false, schema) + s, err := r.reflect(ee.JSONSchemaElse(), rc, false, schema) if err != nil { - return fmt.Errorf("failed to reflect 'else' value of %T: %w", vi, err) + return fmt.Errorf("failed to reflect 'else' value of %T: %w", ee, err) } schema.WithElse(s.ToSchemaOrBool()) @@ -1359,11 +1425,17 @@ type enum struct { // loadFromField loads enum from field tag: json array or comma-separated string. func (enum *enum) loadFromField(fieldTag reflect.StructTag, fieldVal interface{}) { - if e, isEnumer := fieldVal.(NamedEnum); isEnumer { + fv := reflect.ValueOf(fieldVal) + + if e, isEnumer := safeInterface(fv).(NamedEnum); isEnumer { + enum.items, enum.names = e.NamedEnum() + } else if e, isEnumer := ptrTo(fv).(NamedEnum); isEnumer { enum.items, enum.names = e.NamedEnum() } - if e, isEnumer := fieldVal.(Enum); isEnumer { + if e, isEnumer := safeInterface(fv).(Enum); isEnumer { + enum.items = e.Enum() + } else if e, isEnumer := ptrTo(fv).(Enum); isEnumer { enum.items = e.Enum() } diff --git a/reflect_test.go b/reflect_test.go index bce40a6..4524f4e 100644 --- a/reflect_test.go +++ b/reflect_test.go @@ -842,7 +842,7 @@ func TestReflector_Reflect_sub_schema(t *testing.T) { }, "Enumed":{"enum":["foo","bar"],"type":"string"}, "Person":{ - "required":["lastName"], + "title":"Person","required":["lastName"], "properties":{ "birthDate":{"type":"string","format":"date"}, "createdAt":{"type":"string","format":"date-time"}, @@ -1958,6 +1958,7 @@ func TestReflector_Reflect_nilPreparer(t *testing.T) { s, err := r.Reflect(o) require.NoError(t, err) assertjson.EqMarshal(t, `{ + "title":"Organization", "definitions":{ "JsonschemaGoTestEnumed":{"enum":["foo","bar"],"type":"string"}, "JsonschemaGoTestPerson":{ @@ -1984,3 +1985,493 @@ func TestReflector_Reflect_nilPreparer(t *testing.T) { "type":"object" }`, s) } + +type withPtrPreparer string + +func (w *withPtrPreparer) PrepareJSONSchema(schema *jsonschema.Schema) error { + schema.WithTitle(string(*w)) + + return nil +} + +type withValPreparer string + +func (w withValPreparer) PrepareJSONSchema(schema *jsonschema.Schema) error { + schema.WithTitle(string(w)) + + return nil +} + +func TestReflector_Reflect_Preparer(t *testing.T) { + r := jsonschema.Reflector{} + + var ( + np *withPtrPreparer + nv *withValPreparer + ) + + s, err := r.Reflect(np) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"title":"","type":["null","string"]}`, s) + + s, err = r.Reflect(nv) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"title":"","type":["null","string"]}`, s) + + s, err = r.Reflect(withValPreparer("test1")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"title":"test1","type":"string"}`, s) + + s, err = r.Reflect(withPtrPreparer("test2")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"title":"test2","type":"string"}`, s) +} + +type withPtrExposer string + +func (w *withPtrExposer) JSONSchema() (jsonschema.Schema, error) { + s := jsonschema.Schema{} + s.WithTitle(string(*w)) + + return s, nil +} + +type withValExposer string + +func (w withValExposer) JSONSchema() (jsonschema.Schema, error) { + s := jsonschema.Schema{} + s.WithTitle(string(w)) + + return s, nil +} + +func TestReflector_Reflect_Exposer(t *testing.T) { + r := jsonschema.Reflector{} + + var ( + np *withPtrExposer + nv *withValExposer + ) + + s, err := r.Reflect(np) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"title":""}`, s) + + s, err = r.Reflect(nv) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"title":""}`, s) + + s, err = r.Reflect(withValExposer("test1")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"title":"test1"}`, s) + + s, err = r.Reflect(withPtrExposer("test2")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"title":"test2"}`, s) +} + +type withPtrRawExposer string + +func (w *withPtrRawExposer) JSONSchemaBytes() ([]byte, error) { + return []byte(`{"title":"` + string(*w) + `"}`), nil +} + +type withValRawExposer string + +func (w withValRawExposer) JSONSchemaBytes() ([]byte, error) { + return []byte(`{"title":"` + string(w) + `"}`), nil +} + +func TestReflector_Reflect_RawExposer(t *testing.T) { + r := jsonschema.Reflector{} + + var ( + np *withPtrRawExposer + nv *withValRawExposer + ) + + s, err := r.Reflect(np) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"title":""}`, s) + + s, err = r.Reflect(nv) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"title":""}`, s) + + s, err = r.Reflect(withValRawExposer("test1")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"title":"test1"}`, s) + + s, err = r.Reflect(withPtrRawExposer("test2")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"title":"test2"}`, s) +} + +type withPtrEnum string + +func (w *withPtrEnum) Enum() []interface{} { + return []interface{}{string(*w)} +} + +type withValEnum string + +func (w withValEnum) Enum() []interface{} { + return []interface{}{string(w)} +} + +func TestReflector_Reflect_Enum(t *testing.T) { + r := jsonschema.Reflector{} + + var ( + np *withPtrEnum + nv *withValEnum + ) + + s, err := r.Reflect(np) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"enum":[""],"type":["null","string"]}`, s) + + s, err = r.Reflect(nv) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"enum":[""],"type":["null","string"]}`, s) + + s, err = r.Reflect(withValEnum("test1")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"enum":["test1"],"type":"string"}`, s) + + s, err = r.Reflect(withPtrEnum("test2")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"enum":["test2"],"type":"string"}`, s) +} + +type withPtrNamedEnum string + +func (w *withPtrNamedEnum) NamedEnum() ([]interface{}, []string) { + return []interface{}{string(*w)}, []string{"n:" + string(*w)} +} + +type withValNamedEnum string + +func (w withValNamedEnum) NamedEnum() ([]interface{}, []string) { + return []interface{}{string(w)}, []string{"n:" + string(w)} +} + +func TestReflector_Reflect_NamedEnum(t *testing.T) { + r := jsonschema.Reflector{} + + var ( + np *withPtrNamedEnum + nv *withValNamedEnum + ) + + s, err := r.Reflect(np) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"enum":[""],"type":["null","string"],"x-enum-names":["n:"]}`, s) + + s, err = r.Reflect(nv) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"enum":[""],"type":["null","string"],"x-enum-names":["n:"]}`, s) + + s, err = r.Reflect(withValNamedEnum("test1")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"enum":["test1"],"type":"string","x-enum-names":["n:test1"]}`, s) + + s, err = r.Reflect(withPtrNamedEnum("test2")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"enum":["test2"],"type":"string","x-enum-names":["n:test2"]}`, s) +} + +type withPtrOneOfExposer string + +func (w *withPtrOneOfExposer) JSONSchemaOneOf() []interface{} { + return []interface{}{withValPreparer(*w), withPtrPreparer("2:" + *w)} +} + +type withValOneOfExposer string + +func (w withValOneOfExposer) JSONSchemaOneOf() []interface{} { + return []interface{}{withValPreparer(w), withPtrPreparer("2:" + w)} +} + +func TestReflector_Reflect_OneOfExposer(t *testing.T) { + r := jsonschema.Reflector{} + + var ( + np *withPtrOneOfExposer + nv *withValOneOfExposer + ) + + s, err := r.Reflect(np) + require.NoError(t, err) + assertjson.EqMarshal(t, `{ + "type":["null","string"], + "oneOf":[{"title":"","type":"string"},{"title":"2:","type":"string"}] + }`, s) + + s, err = r.Reflect(nv) + require.NoError(t, err) + assertjson.EqMarshal(t, `{ + "type":["null","string"], + "oneOf":[{"title":"","type":"string"},{"title":"2:","type":"string"}] + }`, s) + + s, err = r.Reflect(withValOneOfExposer("test1")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{ + "type":"string", + "oneOf":[{"title":"test1","type":"string"},{"title":"2:test1","type":"string"}] + }`, s) + + s, err = r.Reflect(withPtrOneOfExposer("test2")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{ + "type":"string", + "oneOf":[{"title":"test2","type":"string"},{"title":"2:test2","type":"string"}] + }`, s) +} + +type withPtrAnyOfExposer string + +func (w *withPtrAnyOfExposer) JSONSchemaAnyOf() []interface{} { + return []interface{}{withValPreparer(*w), withPtrPreparer("2:" + *w)} +} + +type withValAnyOfExposer string + +func (w withValAnyOfExposer) JSONSchemaAnyOf() []interface{} { + return []interface{}{withValPreparer(w), withPtrPreparer("2:" + w)} +} + +func TestReflector_Reflect_AnyOfExposer(t *testing.T) { + r := jsonschema.Reflector{} + + var ( + np *withPtrAnyOfExposer + nv *withValAnyOfExposer + ) + + s, err := r.Reflect(np) + require.NoError(t, err) + assertjson.EqMarshal(t, `{ + "type":["null","string"], + "anyOf":[{"title":"","type":"string"},{"title":"2:","type":"string"}] + }`, s) + + s, err = r.Reflect(nv) + require.NoError(t, err) + assertjson.EqMarshal(t, `{ + "type":["null","string"], + "anyOf":[{"title":"","type":"string"},{"title":"2:","type":"string"}] + }`, s) + + s, err = r.Reflect(withValAnyOfExposer("test1")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{ + "type":"string", + "anyOf":[{"title":"test1","type":"string"},{"title":"2:test1","type":"string"}] + }`, s) + + s, err = r.Reflect(withPtrAnyOfExposer("test2")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{ + "type":"string", + "anyOf":[{"title":"test2","type":"string"},{"title":"2:test2","type":"string"}] + }`, s) +} + +type withPtrAllOfExposer string + +func (w *withPtrAllOfExposer) JSONSchemaAllOf() []interface{} { + return []interface{}{withValPreparer(*w), withPtrPreparer("2:" + *w)} +} + +type withValAllOfExposer string + +func (w withValAllOfExposer) JSONSchemaAllOf() []interface{} { + return []interface{}{withValPreparer(w), withPtrPreparer("2:" + w)} +} + +func TestReflector_Reflect_AllOfExposer(t *testing.T) { + r := jsonschema.Reflector{} + + var ( + np *withPtrAllOfExposer + nv *withValAllOfExposer + ) + + s, err := r.Reflect(np) + require.NoError(t, err) + assertjson.EqMarshal(t, `{ + "type":["null","string"], + "allOf":[{"title":"","type":"string"},{"title":"2:","type":"string"}] + }`, s) + + s, err = r.Reflect(nv) + require.NoError(t, err) + assertjson.EqMarshal(t, `{ + "type":["null","string"], + "allOf":[{"title":"","type":"string"},{"title":"2:","type":"string"}] + }`, s) + + s, err = r.Reflect(withValAllOfExposer("test1")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{ + "type":"string", + "allOf":[{"title":"test1","type":"string"},{"title":"2:test1","type":"string"}] + }`, s) + + s, err = r.Reflect(withPtrAllOfExposer("test2")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{ + "type":"string", + "allOf":[{"title":"test2","type":"string"},{"title":"2:test2","type":"string"}] + }`, s) +} + +type withPtrNotExposer string + +func (w *withPtrNotExposer) JSONSchemaNot() interface{} { + return withValPreparer(*w) +} + +type withValNotExposer string + +func (w withValNotExposer) JSONSchemaNot() interface{} { + return withValPreparer(w) +} + +func TestReflector_Reflect_NotExposer(t *testing.T) { + r := jsonschema.Reflector{} + + var ( + np *withPtrNotExposer + nv *withValNotExposer + ) + + s, err := r.Reflect(np) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"type":["null","string"],"not":{"title":"","type":"string"}}`, s) + + s, err = r.Reflect(nv) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"type":["null","string"],"not":{"title":"","type":"string"}}`, s) + + s, err = r.Reflect(withValNotExposer("test1")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"type":"string","not":{"title":"test1","type":"string"}}`, s) + + s, err = r.Reflect(withPtrNotExposer("test2")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"type":"string","not":{"title":"test2","type":"string"}}`, s) +} + +type withPtrIfExposer string + +func (w *withPtrIfExposer) JSONSchemaIf() interface{} { + return withValPreparer(*w) +} + +type withValIfExposer string + +func (w withValIfExposer) JSONSchemaIf() interface{} { + return withValPreparer(w) +} + +func TestReflector_Reflect_IfExposer(t *testing.T) { + r := jsonschema.Reflector{} + + var ( + np *withPtrIfExposer + nv *withValIfExposer + ) + + s, err := r.Reflect(np) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"type":["null","string"],"if":{"title":"","type":"string"}}`, s) + + s, err = r.Reflect(nv) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"type":["null","string"],"if":{"title":"","type":"string"}}`, s) + + s, err = r.Reflect(withValIfExposer("test1")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"type":"string","if":{"title":"test1","type":"string"}}`, s) + + s, err = r.Reflect(withPtrIfExposer("test2")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"type":"string","if":{"title":"test2","type":"string"}}`, s) +} + +type withPtrThenExposer string + +func (w *withPtrThenExposer) JSONSchemaThen() interface{} { + return withValPreparer(*w) +} + +type withValThenExposer string + +func (w withValThenExposer) JSONSchemaThen() interface{} { + return withValPreparer(w) +} + +func TestReflector_Reflect_ThenExposer(t *testing.T) { + r := jsonschema.Reflector{} + + var ( + np *withPtrThenExposer + nv *withValThenExposer + ) + + s, err := r.Reflect(np) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"type":["null","string"],"then":{"title":"","type":"string"}}`, s) + + s, err = r.Reflect(nv) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"type":["null","string"],"then":{"title":"","type":"string"}}`, s) + + s, err = r.Reflect(withValThenExposer("test1")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"type":"string","then":{"title":"test1","type":"string"}}`, s) + + s, err = r.Reflect(withPtrThenExposer("test2")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"type":"string","then":{"title":"test2","type":"string"}}`, s) +} + +type withPtrElseExposer string + +func (w *withPtrElseExposer) JSONSchemaElse() interface{} { + return withValPreparer(*w) +} + +type withValElseExposer string + +func (w withValElseExposer) JSONSchemaElse() interface{} { + return withValPreparer(w) +} + +func TestReflector_Reflect_ElseExposer(t *testing.T) { + r := jsonschema.Reflector{} + + var ( + np *withPtrElseExposer + nv *withValElseExposer + ) + + s, err := r.Reflect(np) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"type":["null","string"],"else":{"title":"","type":"string"}}`, s) + + s, err = r.Reflect(nv) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"type":["null","string"],"else":{"title":"","type":"string"}}`, s) + + s, err = r.Reflect(withValElseExposer("test1")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"type":"string","else":{"title":"test1","type":"string"}}`, s) + + s, err = r.Reflect(withPtrElseExposer("test2")) + require.NoError(t, err) + assertjson.EqMarshal(t, `{"type":"string","else":{"title":"test2","type":"string"}}`, s) +} diff --git a/struct_test.go b/struct_test.go index a7e92ed..1c75bc9 100644 --- a/struct_test.go +++ b/struct_test.go @@ -79,7 +79,7 @@ func TestReflector_Reflect_Struct(t *testing.T) { "definitions":{ "JsonschemaGoTestEnumed":{"enum":["foo","bar"],"type":"string"}, "JsonschemaGoTestPerson":{ - "required":["lastName"], + "title":"Person","required":["lastName"], "properties":{ "birthDate":{"type":"string","format":"date"}, "createdAt":{"type":"string","format":"date-time"},