Skip to content

Migration smithy Part 4 - #3912

Open
sbaluja wants to merge 44 commits into
mainfrom
migration-smithy-3
Open

Migration smithy Part 4#3912
sbaluja wants to merge 44 commits into
mainfrom
migration-smithy-3

Conversation

@sbaluja

@sbaluja sbaluja commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Issue #, if available:

Description of changes:

  • Streaming members/Event stream generation
  • Service level transforms
  • QueryParameters
  • Request Specific Headers
  • OperationContextParams JmesPath traversal
  • Guard windows macros
  • Query compatibility
  • Static AttributeValue class for DynamoDB

Check all that applies:

  • Did a review by yourself.
  • Added proper tests to cover this PR. (If tests are not applicable, explain.)
  • Checked if this PR is a breaking (APIs have been changed) change.
  • Checked if this PR will not introduce cross-platform inconsistent behavior.
  • Checked if this PR would require a ReadMe/Wiki update.

Check which platforms you have built SDK on to verify the correctness of this PR.

  • Linux
  • Windows
  • Android
  • MacOS
  • IOS
  • Other Platforms

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

sbaluja added 30 commits August 19, 2026 14:15
…etadata

Add per-service Smithy model transforms (SourceRegion, Lambda, SQS,
ApiGateway, ApiGatewayV2, EC2) and a shared TransformSupport helper, and
wire them into the ModelCodegenPlugin transform pipeline.

Extend GlobalTransforms to also inject the ResponseMetadata envelope for
awsQueryCompatible services (e.g. SQS = awsJson1_0 + @awsQueryCompatible),
matching legacy C2J CppClientGenerator.addRequestIdToResults. ResponseMetadata
is now reserved via a shared constant and injection fails fast on any modeled
collision rather than silently mis-generating.
…Mapper

Descend through nested list/map shapes so leaf struct/enum headers reach the
generated header even through nested containers (e.g. apigateway
Deployment.apiSummary: Map<String, Map<String, MethodSnapshot>>), matching
C2J's recursive unwrap. Recursion is bounded by container-nesting depth, and
@Sparse still pulls in <aws/crt/Optional.h> at each nested container level.
Emit #if defined(_WIN32) && defined(X) / #undef X guards for enum constants
that collide with a Windows preprocessor macro (DynamoDB IN, EC2 interface,
S3Crt IGNORE), mirroring C2J PlatformAndKeywordSanitizer.PREDEFINED_SYMBOLS_MAPPING
and ModelEnumHeader.vm.
Name result classes and files via ShapeUtil.getResultSuffix instead of a
hardcoded "Result", so services like EC2 emit *Response result classes,
matching the legacy C2J generator.
…Id stamp

Classify @streaming-union events whose sole payload is a single @eventPayload
blob member as header-only blob-carrier events (C2J eventPayloadType == "blob")
and render them via a new EventPayloadRenderer instead of as JSON sub-objects.

Stamp the top-level requestId onto dual-role sub-objects (operation outputs
also referenced as members) for JSON-family protocols, gated out for Query/EC2
which inject ResponseMetadata instead. MemberRenderer now renders the injected
ResponseMetadata envelope as always-present (no HasBeenSet getter, flag true),
initializes required-member flags in useRequiredField contexts, and keeps event
stream / raw streaming payload flags false, matching C2J.
…llisions

Smithy: renameMember fast-fails on member collision, adds jsonName overload
…h jsonName parity

Smithy: drop superseded accessanalyzer + dead cloudsearchdomain collision-map entries
Smithy: failing test for OperationContextParams header declarations

Smithy: port OperationContextCppCodeGenerator string-building helper

Smithy: port CppEndpointsJmesPathVisitor onto Smithy shape types

Smithy: unit tests for OperationContextParams JMESPath visitor

Smithy: emit GetOperationContextParams header decl for OperationContextParamsTrait

Smithy: emit GetEndpointContextParams body and GetOperationContextParams accessor

Smithy: emit Accessor comment before GetOperationContextParams for C2J parity

Smithy: end-to-end tests for OperationContextParams JMESPath patterns

Smithy: reduce OperationContextParams visitor boilerplate via UnsupportedExpressionVisitor base

Smithy: whitespace-tolerant assertions for OperationContextParams visitor tests

Smithy: immutable Emit-based OperationContextParams visitor; drop mutable code generator

Smithy: correct stale accessor-emission comment after immutable redesign
Smithy: EventStreamRenderer emits void() callback typedef for empty events

Smithy: EventStreamRenderer emits arg-less default lambda for empty events

Smithy: EventStreamRenderer dispatches empty events arg-less (no struct construct)

Smithy: ShapeClassifier drops empty-member event structs from subObjects

Smithy: drop incoming event-stream union header from subObjects/render

Smithy: record event-stream empty-event cleanup as accepted parity divergence

Smithy: skip empty-event struct include in event-stream handler header

Smithy: mark event-stream handler-include defect resolved in parity-deltas
…ror methods

- injectAccessLogTagQuery: mark customizedAccessLogTag @httpQueryParams so RestXml
  emits AddQueryStringParameters (was missing on 110 requests)
- new EmbeddedErrorsTrait + S3Transforms.markEmbeddedErrors (C2J functionsWithEmbeddedErrors
  set) + RestXmlProtocolTraits emits HasEmbeddedError under the marker (was missing on 92 requests)
The XML error-sniff body is constant (not shape-dependent) across C2J's S3 request-source
templates, so there is nothing to defer. Move the HasEmbeddedError helpers out of the base
ProtocolTraits (they leaked XML parsing into every protocol) into RestXmlProtocolTraits, where
the marker is the only emit site, and emit the real parse-body / root-is-<Error> logic.
sbaluja added 10 commits August 31, 2026 16:13
Smithy: drop dead CBOR HTTP-binding wiring and correct REQUEST_SOURCE includes

Smithy: share RequestHeaderSerializer value expression across scalar and list paths

Smithy: RPC protocols (awsJson, rpcv2-cbor) do not wire-serialize HTTP-binding members

Smithy: query enums gate on HasBeenSet only (no NOT_SET), matching C2J

Smithy: lowercase request header location names to match C2J

Smithy: S3 customizedAccessLogTag x- query filter

Smithy: dedupe RequestQuerySerializer timestamp stream expression

Smithy: RequestQuerySerializer list and query-params-map serialization

Smithy: RequestHeaderSerializer prefix-header map and list serialization

Smithy: RequestHeaderSerializer scalar header-member serialization
@@ -64,11 +66,13 @@ public void generateAll() {
private List<ShapeRenderer> buildRenderers(ClassifiedShapes classified, RenderContext ctx) {
List<ShapeRenderer> renderers = new ArrayList<>();
renderers.add(new EnumShapeRenderer(classified.enums(), ctx));
renderers.add(new SubObjectRenderer(classified.subObjects(), ctx));
renderers.add(new SubObjectRenderer(classified.subObjects(), classified.resultOutputIds(), ctx));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we are decomposing the SubObjectRenderer to take two members of the same object seems like it should become SubObjectRenderer(classified)

// Future: S3Transforms.asTransform(), Ec2Transforms.asTransform(), etc.
GlobalTransforms.asTransform(),
SourceRegionTransform.asTransform(),
LambdaTransforms.asTransform(),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can some transformers be run in parallel with eachother? and is there a gain for doing as such? LambdaTransforms, SqsTransforms will only ever run on one model so threading a boolean check is not worth the thread, but is there any cases where several that would take a while or could involve i/o run and can be run in parallel? are there any that need to happen in order and require a graph like pipeline?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they can, but there's no real benefit to it. they're all pure in-memory model rewrites, no i/o, and each is gated to a single service so only one really does work per run. also, because of that there is no specific ordering to these transforms.

* service-agnostic.
*/
public final class AdditionalRequestHeadersTrait extends AbstractTrait {
public static final ShapeId ID = ShapeId.from("aws.cpp.internal#additionalRequestHeaders");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so here we are creating traits internal to us. the transforms and renderers are tied together through these synthetic aws.cpp.internal#* traits. im fine with traits being the transport, thats the normal smithy way, but the contract between the two sides is completely implicit and nothing enforces it.

we could actually register them as real smithy traits. right now they have no Provider and no TraitService entry so theyre not first class and wouldnt survive a model round trip. we could give each one a Provider and register it through the SPI.:

// in TopLevelHostIdTrait
public static final class Provider extends AnnotationTrait.Provider<TopLevelHostIdTrait> {
    public Provider() { super(ID, node -> new TopLevelHostIdTrait()); }
}
# src/main/resources/META-INF/services/software.amazon.smithy.model.traits.TraitService
com.amazonaws...transforms.TopLevelHostIdTrait$Provider
com.amazonaws...transforms.ChecksumMemberTrait$Provider
# one per internal trait

kotlin does something very similar to this for their own custom traits.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah agreed these would traits would not survive a round-trip but the round trip never happens here since we stamp them in the transform and read them in the renderer within the same in-memory pass in ModelCodegenPlugin, nothing ever serializes the model back out and re-assembles it. so there's no provider lookup to fail. the traits ride along as plain objects and Model.builder() doesn't validate applied-trait defs. however, if you feel strongly about registering them to enforce the contract + be round-trip safe, i dont mind but it will grow the PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants