Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Perform partial unmarshaling with yaml.DisallowUnknownField() #491

Open
ekoops opened this issue Oct 30, 2024 · 0 comments
Open

Perform partial unmarshaling with yaml.DisallowUnknownField() #491

ekoops opened this issue Oct 30, 2024 · 0 comments

Comments

@ekoops
Copy link

ekoops commented Oct 30, 2024

Is your feature request related to a problem? Please describe.
I would like to use yaml.DisallowUnknownField() while still be able to perform partial unmarshaling.

Describe the solution you'd like

Describe alternatives you've considered

Additional context
The following snippet just try to perform unmarshaling in two steps:

  • unmarshal the type
  • unmarshal the remaining document content based on the type
type T struct {
	Type  string
	Value any
}

type A struct {
	Field1 string
}

type B struct {
	Field2 string
}

func (t *T) UnmarshalYAML(unmarshal func(interface{}) error) error {
	var typ struct{ Type string }
	if err := unmarshal(&typ); err != nil {
		return fmt.Errorf("error decoding type: %w", err)
	}

	decodedType := typ.Type
	var value any
	switch decodedType {
	case "a":
		value = &A{}
	case "b":
		value = &B{}
	default:
		return fmt.Errorf("unknown type %q", decodedType)
	}

	if err := unmarshal(value); err != nil {
		return fmt.Errorf("error decoding value: %w", err)
	}

	t.Type = decodedType
	t.Value = value
	return nil
}

var data = `
type: "a"
value:
    field1: "field1"
`

func main() {
	reader := strings.NewReader(data)
	dec := yaml.NewDecoder(reader, yaml.DisallowUnknownField())
	t := &T{}
	if err := dec.Decode(t); err != nil {
		log.Fatal(err)
	}
}

If I run this, unfortunately, I get the following error:

2009/11/10 23:00:00 error decoding type: [3:1] unknown field "value"
   2 | type: "a"
>  3 | value:
       ^
   4 |     field1: "field1"

The problem is that unmarshal(&typ) looks at the definition of the unnamed structure and see that there are no fields other than Type, so any other field will be treated as unknown, as per yaml.DisallowUnknownField() specification. Is there any solution to this problem?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant