-
Notifications
You must be signed in to change notification settings - Fork 112
Description
Hi there! Thanks a ton for maintaining go-jsonschema
; I've been using it as part of x509-limbo to share types across a common schema.
I'm reporting what I believe to be a regression with v0.18.0, which appears to be caused by improvements made with that release (namely, better handling of anyOf
variants).
In particular, I have a type schema that has a member like this:
"expected_peer_name": {
"anyOf": [
{
"$ref": "#/$defs/PeerName"
},
{
"type": "null"
}
],
"default": null,
"description": "For server (i.e. client-side) validation: the expected peer name, if any"
},
Full source here: https://github.com/C2SP/x509-limbo/blob/main/limbo-schema.json
go-jsonschema
generates the following for this:
// Represents a peer (i.e., end entity) certificate's name (Subject or SAN).
type TestcaseExpectedPeerName struct {
// The kind of peer name
Kind PeerKind `json:"kind" yaml:"kind" mapstructure:"kind"`
// The peer's name
Value string `json:"value" yaml:"value" mapstructure:"value"`
}
// UnmarshalJSON implements json.Unmarshaler.
func (j *TestcaseExpectedPeerName) UnmarshalJSON(value []byte) error {
var raw map[string]interface{}
if err := json.Unmarshal(value, &raw); err != nil {
return err
}
var testcaseExpectedPeerName_0 TestcaseExpectedPeerName_0
var testcaseExpectedPeerName_1 TestcaseExpectedPeerName_1
var errs []error
if err := testcaseExpectedPeerName_0.UnmarshalJSON(value); err != nil {
errs = append(errs, err)
}
if err := testcaseExpectedPeerName_1.UnmarshalJSON(value); err != nil {
errs = append(errs, err)
}
if len(errs) == 2 {
return fmt.Errorf("all validators failed: %s", errors.Join(errs...))
}
type Plain TestcaseExpectedPeerName
var plain Plain
if err := json.Unmarshal(value, &plain); err != nil {
return err
}
*j = TestcaseExpectedPeerName(plain)
return nil
}
In plain English: TestcaseExpectedPeerName
is a duplicate of the PeerName
type, and then the UnmarshalJSON
function attempts to deserialize two variants of it (TestcaseExpectedPeerName_0
and TestcaseExpectedPeerName_1
). However, go-jsonschema
does not generate the TestcaseExpectedPeerName_1
variant, presumably because it has type: null
in the schema:
./schema.go:467:33: undefined: TestcaseExpectedPeerName_1
make: *** [gocryptox509] Error 1
This can be seen in the source as well, where only TestcaseExpectedPeerName_0
is present:
type TestcaseExpectedPeerName_0 = PeerName
Expected behavior
I expected go-jsonschema
to generate well-formed Go code.
In particular, I expected it to generate either an interface{}
type for ExpectedPeerName
(like it did in v0.17.0 and earlier) or generate an appropriate non-variant type (no _0
or _1
at all), since the null
variant should be handled via the omitempty
marker.
Workarounds
Downgrading to v0.17.0 results in correct codegen, although with slightly suboptimal typing (interface{}
instead of a stronger type definition).