Skip to content

Add Smithy shape subclasses for request, response, exception, and mod… - #7239

Open
Fred1155 wants to merge 1 commit into
feature/master/smithy-migrationfrom
bole/add_smithy_shape_subclasses
Open

Add Smithy shape subclasses for request, response, exception, and mod…#7239
Fred1155 wants to merge 1 commit into
feature/master/smithy-migrationfrom
bole/add_smithy_shape_subclasses

Conversation

@Fred1155

@Fred1155 Fred1155 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Motivation and Context

The previous PR #7218 added the AddSmithyShapes base class, which translates a single shape and its members. This PR adds the four concrete processors on top of it — the ones that decide which shapes to translate and stamp the type-specific fields (marshaller, unmarshaller, error code, HTTP status). Each is a port of the matching C2J processor: same output (Map<String, ShapeModel>), different input. Nothing is wired into generation yet.

Modifications

Files

File Role C2J counterpart
smithy/AddSmithyInputShapes.java request shapes + ShapeMarshaller AddInputShapes, AddEmptyInputShape
smithy/AddSmithyOutputShapes.java response shapes + ShapeUnmarshaller AddOutputShapes, AddEmptyOutputShape
smithy/AddSmithyExceptionShapes.java exception shapes AddExceptionShapes
smithy/AddSmithyModelShapes.java remaining reachable shapes AddModelShapes
AddSmithyProcessorsTest (8), AddSmithyInputShapesTest (6), AddSmithyOutputShapesTest (3) coverage

Shape selection

C2J Smithy
iteration serviceModel.getOperations() TopDownIndex.getContainedOperations(service)
input op.getInput() != null; null → AddEmptyInputShape input shape; smithy.api#Unit → synthesized
output op.getOutput() != null; null → AddEmptyOutputShape output shape; Unit → synthesized
exceptions every shape with isException() OperationIndex.getErrors(service, op) — merged service + operation errors, skipping names already emitted
model shapes every shape, exceptions excluded BFS from input/output/errors, following member/list/map targets

Note the exception source is the merged error list, matching what the operation translator uses for OperationModel.exceptions. Reading only op.getErrors() would skip service-level errors and leave an operation referencing an exception class with no shape.

AddSmithyModelShapes additionally skips prelude shapes and @error shapes (owned by the exception processor). C2J skips exceptions the same way (getModelShapeType returns null forisException()).

Union handling matches: C2J models a union as a structure, so it lands as Model; the Smithy processor also maps union → Model (only isEnumShapeEnum).

Request shape

C2J builds the marshaller in Utils.createInputShapeMarshaller /
createSyntheticInputShapeMarshaller.

Field C2J source Smithy source
action operation name same
protocol metadata.getProtocol() resolved protocol passed in
verb / requestUri op.getHttp() @http for rest-json/rest-xml; else POST + / — D1
target metadata.getTargetPrefix() + operation name service shape name + operation name (awsJson/cbor); bare name for query/ec2
locationName / xmlNameSpaceUri operation input reference rebuilt for rest-xml body requests — D2
isSynthetic true from AddEmptyInputShape true for a Unit input
ShapeModel.endpointDiscovery op.getEndpointdiscovery() (AddInputShapes:82) ClientEndpointDiscoveryIndex.getEndpointDiscoveryInfo(service, op)

endpointDiscovery is set only on real input shapes; C2J's AddEmptyInputShape does not set it, so synthesized empty requests stay null. Both SyncClientClass:310 and AsyncClientClass:417 read it off the request shape, guarded only by the operation-level field, so a null there fails codegen rather than producing a diff.

For smithy-rpc-v2-cbor services the request URI produced here is /, while the C2J path produces /service/{targetPrefix}/operation/{OperationName}. C2J doesn't read that path from the model either, it also starts at /, and a customization processor (SmithyRpcV2CborProtocolProcessor) rewrites it afterwards. That processor hasn't been ported to the Smithy side yet, and it closes when the customization processors land, at which point the same rewrite applies to both paths.

Response shape

Field C2J source Smithy source
flattened output shape isFlattened() @xmlFlattened
resultWrapper output.getResultWrapper() operation name + Result, awsQuery only — D3

Exception shapes

Field C2J source Smithy source
type Exception same
errorCode shape.getError().getCode() else shape name @awsQueryError where the protocol allows, else shape name — D4
httpStatusCode error.httpStatusCode @httpError

C2J sets isRetryable / isThrottling here; on the Smithy side the base class already sets both from @retryable (AddSmithyShapes:266), so the processor doesn't repeat it. Same for isFault and the documentation fallback.

Testing

Screenshots (if appropriate)

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Checklist

  • I have read the CONTRIBUTING document
  • Local run of mvn install succeeds
  • My code follows the code style of this project
  • My change requires a change to the Javadoc documentation
  • I have updated the Javadoc documentation accordingly
  • I have added tests to cover my changes
  • All new and existing tests passed
  • I have added a changelog entry. Adding a new entry must be accomplished by running the scripts/new-change script and following the instructions. Commit the new file created by the script in .changes/next-release with your changes.
  • My change is to implement 1.11 parity feature and I have updated LaunchChangelog

License

  • I confirm that this pull request can be released under the Apache 2 license

@Fred1155
Fred1155 requested a review from a team as a code owner August 7, 2026 17:02
@Fred1155
Fred1155 requested a review from davidh44 August 7, 2026 18:41
for (OperationShape op : topDown.getContainedOperations(getService())) {
queue.add(op.getInputShape());
queue.add(op.getOutputShape());
queue.addAll(op.getErrors());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

getErrors() only returns operation-level errors, should we call queue.addAll(getService().getErrorsSet()) after the loop?

nit: getErrors() is deprecated in favor of getErrorsSet()

Comment on lines +92 to +102
for (MemberShape m : shape.members()) {
queue.add(m.getTarget());
}
if (shape.isListShape()) {
queue.add(shape.asListShape().get().getMember().getTarget());
continue;
}
if (shape.isMapShape()) {
queue.add(shape.asMapShape().get().getKey().getTarget());
queue.add(shape.asMapShape().get().getValue().getTarget());
continue;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Seems like shape.members() covers all members already, and the subsequent queue.add() calls are redundant. Maybe we can just simplify to

  if (shape.isListShape() || shape.isMapShape()) {
      continue;
  }

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