Skip to content

Commit b58dcf8

Browse files
authored
codegen: Add support for REST-XML Union responses (aws#993)
Adds support for deserializing REST-XML union resources Fixes aws#939 Related to smithy-lang/smithy#678
1 parent 4947df4 commit b58dcf8

File tree

2 files changed

+63
-6
lines changed

2 files changed

+63
-6
lines changed

codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/JsonShapeDeserVisitor.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,6 @@ protected void deserializeUnion(GenerationContext context, UnionShape shape) {
244244
symbol.getNamespace()
245245
).build();
246246
writer.write("uv = &$T{Tag: key}", unknownMemberSymbol);
247-
writer.writeDocs("TODO: FIX ME");
248-
writer.write("_ = value");
249247
writer.write("break loop");
250248
});
251249
});

codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/XmlShapeDeserVisitor.java

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import software.amazon.smithy.codegen.core.SymbolProvider;
1212
import software.amazon.smithy.go.codegen.GoWriter;
1313
import software.amazon.smithy.go.codegen.SmithyGoDependency;
14+
import software.amazon.smithy.go.codegen.SymbolUtils;
15+
import software.amazon.smithy.go.codegen.UnionGenerator;
1416
import software.amazon.smithy.go.codegen.integration.DocumentShapeDeserVisitor;
1517
import software.amazon.smithy.go.codegen.integration.ProtocolGenerator;
1618
import software.amazon.smithy.go.codegen.integration.ProtocolGenerator.GenerationContext;
@@ -404,10 +406,67 @@ protected void deserializeDocument(GenerationContext context, DocumentShape shap
404406
@Override
405407
protected void deserializeUnion(GenerationContext context, UnionShape shape) {
406408
GoWriter writer = context.getWriter();
407-
// TODO: implement union deserialization
408-
// The tricky part is going to be accumulating bytes for unknown members.
409-
LOGGER.warning("Union type is currently unsupported for XML deserialization.");
410-
context.getWriter().writeDocs("TODO: implement union serialization.");
409+
SymbolProvider symbolProvider = context.getSymbolProvider();
410+
Symbol symbol = symbolProvider.toSymbol(shape);
411+
Model model = context.getModel();
412+
413+
writer.write("var uv $P", symbol);
414+
writer.write("var memberFound bool");
415+
416+
// Iterate through the decoder. The member visitor will handle popping
417+
// xml tokens enclosed within a xml start and end element.
418+
writer.openBlock("for {", "}", () -> {
419+
writer.write("t, done, err := decoder.Token()");
420+
writer.write("if err != nil { return err }");
421+
writer.write("if done { break }");
422+
writer.openBlock("if memberFound {", "}", () -> {
423+
writer.write("if err = decoder.Decoder.Skip(); err != nil { return err }");
424+
});
425+
426+
// Create a new decoder for each member
427+
writer.write("originalDecoder := decoder");
428+
writer.write("decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t)");
429+
writer.insertTrailingNewline();
430+
431+
writer.openBlock("switch {", "}", () -> {
432+
Set<MemberShape> members = new TreeSet<>(shape.members());
433+
for (MemberShape member : members) {
434+
// check if member is not a document binding or has a xmlAttribute trait
435+
if (!memberFilter.test(member) || member.hasTrait(XmlAttributeTrait.ID)) {
436+
continue;
437+
}
438+
Symbol targetSymbol = symbolProvider.toSymbol(member);
439+
Symbol memberSymbol = SymbolUtils.createValueSymbolBuilder(
440+
symbolProvider.toMemberName(member),
441+
symbol.getNamespace()
442+
).build();
443+
444+
writer.addUseImports(SmithyGoDependency.STRINGS);
445+
446+
String serializedMemberName = getSerializedMemberName(member);
447+
writer.openBlock("case strings.EqualFold($S, t.Name.Local):", "", serializedMemberName, () -> {
448+
writer.write("var mv $P", targetSymbol);
449+
model.expectShape(member.getTarget()).accept(getMemberDeserVisitor(member, "mv", false));
450+
writer.write("uv = &$T{Value: mv}", memberSymbol);
451+
writer.write("memberFound = true");
452+
});
453+
}
454+
455+
writer.openBlock("default:", "", () -> {
456+
// This is the function to take a value and convert it to the union type.
457+
Symbol unknownMemberSymbol = SymbolUtils.createValueSymbolBuilder(
458+
UnionGenerator.UNKNOWN_MEMBER_NAME,
459+
symbol.getNamespace()
460+
).build();
461+
writer.write("uv = &$T{Tag: t.Name.Local}", unknownMemberSymbol);
462+
writer.write("memberFound = true");
463+
});
464+
});
465+
// re-assign the original decoder
466+
writer.write("decoder = originalDecoder");
467+
});
468+
469+
writer.write("*v = uv");
411470
writer.write("return nil");
412471
}
413472
}

0 commit comments

Comments
 (0)