omissis/go-jsonschema

A generated `AdditionalProperties` doesn't have a struct tag

jamietanna opened this issue · 2 comments

At least for JSON and YAML, I'd expect:

					"additionalProperties": {
						"type": "string"
					}

Would convert into the following Go:

	AdditionalProperties map[string]string `json:"-"`

But instead we see:

	AdditionalProperties map[string]string

Which means that (un)marshaling fails to capture the required fields

Hey @jamietanna, thanks for opening this issue. I am not sure I understand this use-case, could you elaborate a bit more please? eg: why would additional properties need to be omitted? and how does including them causes the failure in capturing the required fields?

Perhaps a full marshaling+unmarshaling example could help, thanks! 😁

I'm facing the same problem, no additionalProperties are being unmarshalled, rendering them unusable.

E.g. having a schema.json

{
    "type": "object",
    "additionalProperties": {
        "type": "object",
        "properties": {
            "property1": {
                "type": "string"
            },
            "property2": {
                "type": "number"
            }
        }
    },
    "properties": {
        "foo": {
            "type": "string"
        },
        "bar": {
            "type": "string"
        }
    }
}

after calling go-jsonschema schema.json --output schema.go --package gen --tags yaml --extra-imports

the Go code is:

// Code generated by github.com/atombender/go-jsonschema, DO NOT EDIT.

package gen

import "encoding/json"
import yaml "gopkg.in/yaml.v3"

type TestJson struct {
	// Bar corresponds to the JSON schema field "bar".
	Bar *string `yaml:"bar,omitempty"`

	// Foo corresponds to the JSON schema field "foo".
	Foo *string `yaml:"foo,omitempty"`

	AdditionalProperties map[string]interface{}
}

// UnmarshalJSON implements json.Unmarshaler.
func (j *TestJson) UnmarshalJSON(b []byte) error {
	var raw map[string]interface{}
	if err := json.Unmarshal(b, &raw); err != nil {
		return err
	}
	type Plain TestJson
	var plain Plain
	if err := json.Unmarshal(b, &plain); err != nil {
		return err
	}
	if v, ok := raw[""]; !ok || v == nil {
		plain.AdditionalProperties = map[string]interface{}{}
	}
	*j = TestJson(plain)
	return nil
}

// UnmarshalYAML implements yaml.Unmarshaler.
func (j *TestJson) UnmarshalYAML(value *yaml.Node) error {
	var raw map[string]interface{}
	if err := value.Decode(&raw); err != nil {
		return err
	}
	type Plain TestJson
	var plain Plain
	if err := value.Decode(&plain); err != nil {
		return err
	}
	if v, ok := raw[""]; !ok || v == nil {
		plain.AdditionalProperties = map[string]interface{}{}
	}
	*j = TestJson(plain)
	return nil
}

Then a test unmarshalling the following test.yaml:

foo: "foo value"
bar: "bar value"
property1: "additional property 1"
property2: "additional property 2"

fails since "property1" and "property2" are not read into Go struct.

Go test code:

t.Run("test", func(t *testing.T) {
		var yamlNode yaml3.Node
		file, _ := os.ReadFile("test.yaml")
		yaml3.Unmarshal(file, &yamlNode)

		genStruct := gen.TestJson{}

		genStruct.UnmarshalYAML(&yamlNode)
		if len(genStruct.AdditionalProperties) == 0 {
			t.Fatalf("no additional properties")
		}
	})