go-jsonschema
go-jsonschema copied to clipboard
Multiple refs to enums results in multiple interfaces
Given a schema like:
{
"$schema": "https://json-schema.org/draft/2019-09/schema",
"title": "test",
"definitions": {
"Foo1": {
"type": "object",
"required": [
"bar"
],
"properties": {
"bar": {
"$ref": "#/definitions/Bar"
}
}
},
"Foo2": {
"type": "object",
"required": [
"bar"
],
"properties": {
"bar": {
"$ref": "#/definitions/Bar"
}
}
},
"Bar": {
"type": "string",
"enum": [
"1",
"2"
]
}
}
}
I.e. Foo1
and Foo2
both have a bar
field of type Bar
, which is an enum.
then the output has three different Bar
types:
Long code snippet
package main
import "fmt"
import "reflect"
import "encoding/json"
type Bar string
// UnmarshalJSON implements json.Unmarshaler.
func (j *Bar_2) UnmarshalJSON(b []byte) error {
var v string
if err := json.Unmarshal(b, &v); err != nil {
return err
}
var ok bool
for _, expected := range enumValues_Bar_2 {
if reflect.DeepEqual(v, expected) {
ok = true
break
}
}
if !ok {
return fmt.Errorf("invalid value (expected one of %#v): %#v", enumValues_Bar_2, v)
}
*j = Bar_2(v)
return nil
}
// UnmarshalJSON implements json.Unmarshaler.
func (j *Bar) UnmarshalJSON(b []byte) error {
var v string
if err := json.Unmarshal(b, &v); err != nil {
return err
}
var ok bool
for _, expected := range enumValues_Bar {
if reflect.DeepEqual(v, expected) {
ok = true
break
}
}
if !ok {
return fmt.Errorf("invalid value (expected one of %#v): %#v", enumValues_Bar, v)
}
*j = Bar(v)
return nil
}
const BarA1 Bar = "1"
const BarA2 Bar = "2"
type Bar_1 string
// UnmarshalJSON implements json.Unmarshaler.
func (j *Foo1) UnmarshalJSON(b []byte) error {
var raw map[string]interface{}
if err := json.Unmarshal(b, &raw); err != nil {
return err
}
if v, ok := raw["bar"]; !ok || v == nil {
return fmt.Errorf("field bar: required")
}
type Plain Foo1
var plain Plain
if err := json.Unmarshal(b, &plain); err != nil {
return err
}
*j = Foo1(plain)
return nil
}
// UnmarshalJSON implements json.Unmarshaler.
func (j *Bar_1) UnmarshalJSON(b []byte) error {
var v string
if err := json.Unmarshal(b, &v); err != nil {
return err
}
var ok bool
for _, expected := range enumValues_Bar_1 {
if reflect.DeepEqual(v, expected) {
ok = true
break
}
}
if !ok {
return fmt.Errorf("invalid value (expected one of %#v): %#v", enumValues_Bar_1, v)
}
*j = Bar_1(v)
return nil
}
const Bar_1_A1 Bar_1 = "1"
const Bar_1_A2 Bar_1 = "2"
type Bar_2 string
const Bar_2_A1 Bar_2 = "1"
const Bar_2_A2 Bar_2 = "2"
type Foo1 struct {
// Bar corresponds to the JSON schema field "bar".
Bar Bar_1 `json:"bar"`
}
type Foo2 struct {
// Bar corresponds to the JSON schema field "bar".
Bar Bar_2 `json:"bar"`
}
var enumValues_Bar = []interface{}{
"1",
"2",
}
var enumValues_Bar_1 = []interface{}{
"1",
"2",
}
var enumValues_Bar_2 = []interface{}{
"1",
"2",
}
// UnmarshalJSON implements json.Unmarshaler.
func (j *Foo2) UnmarshalJSON(b []byte) error {
var raw map[string]interface{}
if err := json.Unmarshal(b, &raw); err != nil {
return err
}
if v, ok := raw["bar"]; !ok || v == nil {
return fmt.Errorf("field bar: required")
}
type Plain Foo2
var plain Plain
if err := json.Unmarshal(b, &plain); err != nil {
return err
}
*j = Foo2(plain)
return nil
}
Expected: there is a single Bar
type shared between the definitions.
One may see the same behaviour even when enum is referenced from one place and in can be seen in tests/data/core/refToEnum.json
and corresponding tests/data/core/refToEnum.go.output
. I think that the reason is that for object types special measures were taken to not declare referenced type twice (https://github.com/atombender/go-jsonschema/blame/master/pkg/generator/generate.go#L427) but not for enums.