1
0
mirror of https://github.com/golang/go synced 2024-11-24 22:47:58 -07:00

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.
This commit is contained in:
Silke Hofstra 2021-09-25 15:44:33 +02:00
parent 740a490f71
commit 16f22f78ca
2 changed files with 18 additions and 9 deletions

View File

@ -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()

View File

@ -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: `<MarshalerStruct Foo="hello world"></MarshalerStruct>`,
Value: &MarshalerStruct{},
},
{
ExpectXML: `<IMarshalerStruct Foo="hello world"></IMarshalerStruct>`,
Value: &IMarshalerStruct{Foo: &MyMarshalerAttrTest{}},
MarshalOnly: true,
},
{
ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
Value: &OuterStruct{IntAttr: 10},