From 16f22f78caa3c02f67fe34b6468040f58f0a788d Mon Sep 17 00:00:00 2001 From: Silke Hofstra Date: Sat, 25 Sep 2021 15:44:33 +0200 Subject: [PATCH] encoding/xml: fix 'unsupported type' error on interface{} attributes When given interface value that is actually a type implementing `encoding.TextMarshaler` or `xml.MarshalerAttr`, `marshalAttr` would return an `unsupported type` error. The cause of this is that pointer and interface values are dereferences after checking if the supported interfaces are implemented. Solve this by moving the dereference of the pointer and interface values to the start of the function, and update the test cases to test for this situation. --- src/encoding/xml/marshal.go | 18 +++++++++--------- src/encoding/xml/marshal_test.go | 9 +++++++++ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/encoding/xml/marshal.go b/src/encoding/xml/marshal.go index 01f673a851..1e1ec396ee 100644 --- a/src/encoding/xml/marshal.go +++ b/src/encoding/xml/marshal.go @@ -555,6 +555,15 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat // marshalAttr marshals an attribute with the given name and value, adding to start.Attr. func (p *printer) marshalAttr(start *StartElement, name Name, val reflect.Value) error { + // Dereference or skip nil pointer, interface values. + switch val.Kind() { + case reflect.Pointer, reflect.Interface: + if val.IsNil() { + return nil + } + val = val.Elem() + } + if val.CanInterface() && val.Type().Implements(marshalerAttrType) { attr, err := val.Interface().(MarshalerAttr).MarshalXMLAttr(name) if err != nil { @@ -601,15 +610,6 @@ func (p *printer) marshalAttr(start *StartElement, name Name, val reflect.Value) } } - // Dereference or skip nil pointer, interface values. - switch val.Kind() { - case reflect.Pointer, reflect.Interface: - if val.IsNil() { - return nil - } - val = val.Elem() - } - // Walk slices. if val.Kind() == reflect.Slice && val.Type().Elem().Kind() != reflect.Uint8 { n := val.Len() diff --git a/src/encoding/xml/marshal_test.go b/src/encoding/xml/marshal_test.go index 3fe7e2dc00..6d6174fe90 100644 --- a/src/encoding/xml/marshal_test.go +++ b/src/encoding/xml/marshal_test.go @@ -343,6 +343,10 @@ type MarshalerStruct struct { Foo MyMarshalerAttrTest `xml:",attr"` } +type IMarshalerStruct struct { + Foo interface{} `xml:",attr"` +} + type InnerStruct struct { XMLName Name `xml:"testns outer"` } @@ -1252,6 +1256,11 @@ var marshalTests = []struct { ExpectXML: ``, Value: &MarshalerStruct{}, }, + { + ExpectXML: ``, + Value: &IMarshalerStruct{Foo: &MyMarshalerAttrTest{}}, + MarshalOnly: true, + }, { ExpectXML: ``, Value: &OuterStruct{IntAttr: 10},