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

MarshalText interface is ignored on nested structs #959

Open
TheFriendlyCoder opened this issue Apr 27, 2023 · 4 comments
Open

MarshalText interface is ignored on nested structs #959

TheFriendlyCoder opened this issue Apr 27, 2023 · 4 comments

Comments

@TheFriendlyCoder
Copy link

Given the following example structs:

type MyChild struct {
	nested   string
}

func (c *MyChild) MarshalText() ([]byte, error) {
	return []byte(c.nested), nil
}

type MyParent struct {
	Child MyChild
}

If you attempt to marshal an instance of MyParent to YAML by doing something like this:

c := MyChild{
	nested: "Hello",
}
p := MyParent{
	Child: c,
}

data, _ := yaml.Marshal(&p)
fmt.Printf("%+v\n", string(data))

You get the following output:

child: {}

Instead of the expected output of:

child:
    nested: Hello

If, however, you attempt to marshal and instance of the MyChild struct directly, as in:

data, _ := yaml.Marshal(&c)
fmt.Printf("%+v\n", string(data))

You get the expected output:

Hello
@TheFriendlyCoder
Copy link
Author

NOTE: It appears as though the MarshalYAML() interface is also ignored on child / nested structs as well, as in the following example:

func (c *MyChild) MarshalYAML() (interface{}, error) {
	return []byte(c.nested), nil
}

@TheFriendlyCoder
Copy link
Author

I did a bit more ad-hoc testing on this issue, and the problem seems to be related to whether the marshaller method takes a pointer or reference receiver. Using the sample code from above, if I have a struct that contains a reference to a value object, then the marshaller method needs to have a reference receiver:

type MyChild struct {
	nested   string
}

func (c MyChild) MarshalText() ([]byte, error) {       // <----- notice the reference receiver "c MyChild"
	return []byte(c.nested), nil
}

type MyParent struct {
	Child MyChild                   // <----- notice the reference value here
}

Similarly, if I have a struct that contains a pointer to a value instead of a reference, the marshaller interface must use a pointer-receiver as in:

type MyChild struct {
	nested   string
}

func (c *MyChild) MarshalText() ([]byte, error) {           // <----- notice the pointer receiver here "c *MyChild"
	return []byte(c.nested), nil
}

type MyParent struct {
	Child *MyChild          // <------- notice the pointer to the value here
}

The issue then becomes, how can one implement a marshal implementation for a structure so as to allow both reference and pointer values to be serialized properly?

@KhanMechAI
Copy link

I did a bit more ad-hoc testing on this issue, and the problem seems to be related to whether the marshaller method takes a pointer or reference receiver. Using the sample code from above, if I have a struct that contains a reference to a value object, then the marshaller method needs to have a reference receiver:

type MyChild struct {
	nested   string
}

func (c MyChild) MarshalText() ([]byte, error) {       // <----- notice the reference receiver "c MyChild"
	return []byte(c.nested), nil
}

type MyParent struct {
	Child MyChild                   // <----- notice the reference value here
}

Similarly, if I have a struct that contains a pointer to a value instead of a reference, the marshaller interface must use a pointer-receiver as in:

type MyChild struct {
	nested   string
}

func (c *MyChild) MarshalText() ([]byte, error) {           // <----- notice the pointer receiver here "c *MyChild"
	return []byte(c.nested), nil
}

type MyParent struct {
	Child *MyChild          // <------- notice the pointer to the value here
}

The issue then becomes, how can one implement a marshal implementation for a structure so as to allow both reference and pointer values to be serialized properly?

I can confirm this is the case

@aathan
Copy link

aathan commented Aug 9, 2023

See #979

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

No branches or pull requests

3 participants