Skip to content

Commit

Permalink
private/protocol/xml/xmlutil: Fix SDK marshaling of empty types (aws#…
Browse files Browse the repository at this point in the history
…2081)

Fixes the SDK's marshaling of types without members. This corrects the
issue where the SDK would not marshal an XML tag for a type, if that
type did not have any exported members.

Fix aws#2015
  • Loading branch information
jasdel authored and Igor Ch committed Sep 23, 2018
1 parent b9ae3fe commit ed50a20
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 6 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG_PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@
* Adds workaround to correct the endpoint for Application Autoscaling running in AWS China. This will allow your application to make API calls to Application Autoscaling service in AWS China.
* Fixes [#2079](https://github.com/aws/aws-sdk-go/issues/2079)
* Fixes [#1957](https://github.com/aws/aws-sdk-go/issues/1957)
* `private/protocol/xml/xmlutil`: Fix SDK marshaling of empty types ([#2081](https://github.com/aws/aws-sdk-go/pull/2081))
* Fixes the SDK's marshaling of types without members. This corrects the issue where the SDK would not marshal an XML tag for a type, if that type did not have any exported members.
* Fixes [#2015](https://github.com/aws/aws-sdk-go/issues/2015)
12 changes: 7 additions & 5 deletions private/protocol/xml/xmlutil/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,6 @@ func (b *xmlBuilder) buildStruct(value reflect.Value, current *XMLNode, tag refl
return nil
}

fieldAdded := false

// unwrap payloads
if payload := tag.Get("payload"); payload != "" {
field, _ := value.Type().FieldByName(payload)
Expand Down Expand Up @@ -123,6 +121,8 @@ func (b *xmlBuilder) buildStruct(value reflect.Value, current *XMLNode, tag refl
child.Attr = append(child.Attr, ns)
}

var payloadFields, nonPayloadFields int

t := value.Type()
for i := 0; i < value.NumField(); i++ {
member := elemOf(value.Field(i))
Expand All @@ -137,8 +137,10 @@ func (b *xmlBuilder) buildStruct(value reflect.Value, current *XMLNode, tag refl

mTag := field.Tag
if mTag.Get("location") != "" { // skip non-body members
nonPayloadFields++
continue
}
payloadFields++

if protocol.CanSetIdempotencyToken(value.Field(i), field) {
token := protocol.GetIdempotencyToken()
Expand All @@ -153,11 +155,11 @@ func (b *xmlBuilder) buildStruct(value reflect.Value, current *XMLNode, tag refl
if err := b.buildValue(member, child, mTag); err != nil {
return err
}

fieldAdded = true
}

if fieldAdded { // only append this child if we have one ore more valid members
// Only case where the child shape is not added is if the shape only contains
// non-payload fields, e.g headers/query.
if !(payloadFields == 0 && nonPayloadFields > 0) {
current.AddChild(child)
}

Expand Down
63 changes: 62 additions & 1 deletion private/protocol/xml/xmlutil/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,44 @@ type explicitPayload struct {
Second *nestedType `type:"structure" locationName:"Second"`
}

type useEmptyNested struct {
_ struct{} `type:"structure" locationName:"useEmptyNested"`

StrVal *string `type:"string"`
Empty *emptyType `type:"structure"`
}

type useIgnoreNested struct {
_ struct{} `type:"structure" locationName:"useIgnoreNested"`
StrVal *string `type:"string"`
Ignore *ignoreNested `type:"structure"`
}

type skipNonPayload struct {
_ struct{} `type:"structure" locationName:"skipNonPayload"`
Field *string `type:"string" location:"header"`
}
type namedEmptyPayload struct {
_ struct{} `type:"structure" locationName:"namedEmptyPayload"`
}

type nestedType struct {
_ struct{} `type:"structure"`

IntVal *int64 `type:"integer"`
StrVal *string `type:"string"`
}

type emptyType struct {
_ struct{} `type:"structure"`
}

type ignoreNested struct {
_ struct{} `type:"structure"`

IgnoreMe *string `type:"string" ignore:"true"`
}

func TestBuildXML(t *testing.T) {
cases := map[string]struct {
Input interface{}
Expand Down Expand Up @@ -81,7 +112,7 @@ func TestBuildXML(t *testing.T) {
},
Expect: `<namedPayload><Second><IntVal>1111</IntVal><StrVal>second string</StrVal></Second><StrVal>string value</StrVal><Third><IntVal>2222</IntVal><StrVal>third string</StrVal></Third></namedPayload>`,
},
"empty nested type": {
"empty with fields nested type": {
Input: &namedImplicitPayload{
StrVal: aws.String("string value"),
Second: &nestedType{},
Expand All @@ -92,6 +123,36 @@ func TestBuildXML(t *testing.T) {
},
Expect: `<namedPayload><Second></Second><StrVal>string value</StrVal><Third><IntVal>2222</IntVal><StrVal>third string</StrVal></Third></namedPayload>`,
},
"empty no fields nested type": {
Input: &useEmptyNested{
StrVal: aws.String("string value"),
Empty: &emptyType{},
},
Expect: `<useEmptyNested><Empty></Empty><StrVal>string value</StrVal></useEmptyNested>`,
},
"ignored nested field": {
Input: &useIgnoreNested{
StrVal: aws.String("string value"),
Ignore: &ignoreNested{
IgnoreMe: aws.String("abc123"),
},
},
Expect: `<useIgnoreNested><Ignore></Ignore><StrVal>string value</StrVal></useIgnoreNested>`,
},
"skip non payload root": {
Input: &skipNonPayload{
Field: aws.String("value"),
},
Expect: "",
},
"skip empty root": {
Input: &emptyType{},
Expect: "",
},
"named empty payload": {
Input: &namedEmptyPayload{},
Expect: "<namedEmptyPayload></namedEmptyPayload>",
},
}

for name, c := range cases {
Expand Down

0 comments on commit ed50a20

Please sign in to comment.