From f77e736819779512a0f39de872fe3b7c0d735a19 Mon Sep 17 00:00:00 2001 From: Dmitriy Musatkin <63878209+DmitriyMusatkin@users.noreply.github.com> Date: Fri, 26 Jul 2024 10:41:14 -0700 Subject: [PATCH] Fix codegen for implicit event payloads with a single enum field (#3056) * update codegen for enums --- .../aws/qbusiness/model/ChatInputStream.h | 5 ++- .../C2jModelToGeneratorModelTransformer.java | 29 ++++++++++-- ...jModelToGeneratorModelTransformerTest.java | 44 +++++++++++++++++-- 3 files changed, 70 insertions(+), 8 deletions(-) diff --git a/generated/src/aws-cpp-sdk-qbusiness/include/aws/qbusiness/model/ChatInputStream.h b/generated/src/aws-cpp-sdk-qbusiness/include/aws/qbusiness/model/ChatInputStream.h index 402293f6e92..92455dee2cb 100644 --- a/generated/src/aws-cpp-sdk-qbusiness/include/aws/qbusiness/model/ChatInputStream.h +++ b/generated/src/aws-cpp-sdk-qbusiness/include/aws/qbusiness/model/ChatInputStream.h @@ -23,7 +23,7 @@ namespace Model { /** - *

The streaming input for the Chat API.

See Also:

+ *

The streaming input for the Chat API.

See Also:

* AWS * API Reference

@@ -85,7 +85,8 @@ namespace Model Aws::Utils::Event::Message msg; msg.InsertEventHeader(":message-type", Aws::String("event")); msg.InsertEventHeader(":event-type", Aws::String("AuthChallengeResponseEvent")); - AWS_UNREFERENCED_PARAM(value); + msg.InsertEventHeader(":content-type", Aws::String("application/json")); + msg.WriteEventPayload(value.Jsonize().View().WriteCompact()); WriteEvent(msg); return *this; } diff --git a/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/transform/C2jModelToGeneratorModelTransformer.java b/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/transform/C2jModelToGeneratorModelTransformer.java index 050c776fcb9..0c95e6c8cc2 100644 --- a/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/transform/C2jModelToGeneratorModelTransformer.java +++ b/tools/code-generation/generator/src/main/java/com/amazonaws/util/awsclientgenerator/transform/C2jModelToGeneratorModelTransformer.java @@ -305,9 +305,32 @@ header insertion there. So strip this out of the model (affects S3's PutObjectR } else if (shape.hasEventPayloadMembers() || shape.getMembers().size() == 1) { if (shape.getMembers().size() == 1) { shape.getMembers().entrySet().stream().forEach(memberEntry -> { - memberEntry.getValue().setEventPayload(true); - shape.setEventPayloadMemberName(memberEntry.getKey()); - shape.setEventPayloadType(memberEntry.getValue().getShape().getType()); + /** + * Note: this is complicated and potentially not completely correct. + * So touch at your own risk until we have protocol tests supported. + * In summary: + * - we need to determine how to serialize events in eventstream + * - to specify payload there is an eventpayload trait + * - but what happens if that trait is not specified + * - if there is one field and its a string, blob or struct then we assume that field is event payload + * (note: this might not be completely correct, spec is vague on that and other sdks do implicit struct around string and blob) + * - if that one field is of any other type then treat parent shape as eventpayload + * - if there is more than one field then parent shape is the payload + */ + Shape memberShape = memberEntry.getValue().getShape(); + if (memberShape.isString() || + memberShape.isBlob() || + memberShape.isStructure()) { + memberEntry.getValue().setEventPayload(true); + shape.setEventPayloadMemberName(memberEntry.getKey()); + shape.setEventPayloadType(memberShape.getType()); + } else { + if (!shape.getType().equals("structure")) { + throw new RuntimeException("Event shape should always has \"structure\" type if single member cannot be event payload."); + } + shape.setEventPayloadType(shape.getType()); + } + }); } else { throw new RuntimeException("Event shape used in Event Stream should only has one member if it has event payload member."); diff --git a/tools/code-generation/generator/src/test/java/com/amazonaws/util/awsclientgenerator/transform/C2jModelToGeneratorModelTransformerTest.java b/tools/code-generation/generator/src/test/java/com/amazonaws/util/awsclientgenerator/transform/C2jModelToGeneratorModelTransformerTest.java index 223dcc1a8a6..3fd2aa272e7 100644 --- a/tools/code-generation/generator/src/test/java/com/amazonaws/util/awsclientgenerator/transform/C2jModelToGeneratorModelTransformerTest.java +++ b/tools/code-generation/generator/src/test/java/com/amazonaws/util/awsclientgenerator/transform/C2jModelToGeneratorModelTransformerTest.java @@ -13,8 +13,10 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.Map; +import com.google.common.collect.ImmutableList; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertEquals; public class C2jModelToGeneratorModelTransformerTest { @@ -342,7 +344,8 @@ public void testOperationConversion() { // "EventStreamShape":{ // "type":"structure", // "members":{ - // "EventShape":{"shape":"EventShape"} + // "EventShape":{"shape":"EventShape"}, + // "EventEnumShape":{"shape":"EventEnumShape"} // }, // "eventstream":true // }, @@ -353,6 +356,17 @@ public void testOperationConversion() { // }, // "event":true // }, + // "EventEnumShape":{ + // "type":"structure", + // "members":{ + // "BlobShape":{"shape":"BlobShape"} + // }, + // "event":true + // }, + // "EnumShape":{ + // "type":"string", + // "enum":[VALUE] + // } // "BlobShape":{ // "type":"blob" // } @@ -390,6 +404,27 @@ public void testEventStreamShapeConversion() { eventStreamShape.setMembers(new HashMap<>()); eventStreamShape.getMembers().put("EventShape", eventShapeMember); + C2jShape eventEnumShape = new C2jShape(); + eventEnumShape.setType("structure"); + eventEnumShape.setEvent(true); + c2jShapeMap.put("EventEnumShape", eventEnumShape); + + C2jShape enumShape = new C2jShape(); + enumShape.setType("string"); + enumShape.setEnums(ImmutableList.of("VALUE")); + c2jShapeMap.put("EnumShape", enumShape); + + C2jShapeMember enumShapeMember = new C2jShapeMember(); + enumShapeMember.setShape("EnumShape"); + + eventEnumShape.setMembers(new HashMap<>()); + eventEnumShape.getMembers().put("EnumShape", enumShapeMember); + + C2jShapeMember eventEnumShapeMember = new C2jShapeMember(); + eventEnumShapeMember.setShape("EventEnumShape"); + + eventStreamShape.getMembers().put("EvenEnumShape", eventEnumShapeMember); + c2jServiceModel.setShapes(c2jShapeMap); C2jModelToGeneratorModelTransformer c2jModelToGeneratorModelTransformer = new C2jModelToGeneratorModelTransformer(c2jServiceModel, false); @@ -397,7 +432,7 @@ public void testEventStreamShapeConversion() { c2jModelToGeneratorModelTransformer.postProcessShapes(); Map shapes = c2jModelToGeneratorModelTransformer.shapes; - assertEquals(3, shapes.size()); + assertEquals(5, shapes.size()); assertEquals("EventStreamShape", shapes.get("EventStreamShape").getName()); assertTrue(shapes.get("EventStreamShape").isEventStream()); assertEquals("EventShape", shapes.get("EventShape").getName()); @@ -406,10 +441,13 @@ public void testEventStreamShapeConversion() { assertEquals("BlobShape", shapes.get("EventShape").getEventPayloadMemberName()); assertEquals("BlobShape", shapes.get("BlobShape").getName()); assertEquals("blob", shapes.get("BlobShape").getType()); - assertEquals(1, shapes.get("EventStreamShape").getMembers().size()); + assertEquals(2, shapes.get("EventStreamShape").getMembers().size()); assertEquals("EventShape", shapes.get("EventStreamShape").getMembers().get("EventShape").getShape().getName()); assertEquals(1, shapes.get("EventShape").getMembers().size()); assertEquals("BlobShape", shapes.get("EventShape").getMembers().get("BlobShape").getShape().getName()); assertTrue(shapes.get("EventShape").getMembers().get("BlobShape").isEventPayload()); + + assertFalse(shapes.get("EventEnumShape").getMembers().get("EnumShape").isEventPayload()); + assertEquals("structure", shapes.get("EventEnumShape").getEventPayloadType()); } }