Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
036a5a3
Smithy: per-service model transforms and awsQueryCompatible ResponseM…
sbaluja Aug 19, 2026
e61fa21
Smithy: recursively include nested container element types in CppType…
sbaluja Aug 19, 2026
f0c62c1
Smithy: guard Windows-macro-colliding enum constants in EnumRenderer
sbaluja Aug 19, 2026
7a48648
Smithy: honor per-service result-class suffix in ResultRenderer
sbaluja Aug 19, 2026
75e457a
Smithy: blob-payload event rendering and dual-role sub-object request…
sbaluja Aug 19, 2026
34f7dce
Smithy: EC2 transforms fast-fail on Result/Response and SecureBlob co…
sbaluja Aug 24, 2026
4b8e193
Smithy: wire reserved request-member rename with raw-smithy-name skip…
sbaluja Aug 24, 2026
1e0e6da
Smithy: AccessAnalyzerTransforms renames GeneratedPolicyResult(s) wit…
sbaluja Aug 24, 2026
2df9ef7
Carry over serde traits when we rename members
sbaluja Aug 26, 2026
e1a2763
Smithy: add static DynamoDB AttributeValue resource bodies
sbaluja Aug 27, 2026
6222513
Smithy: DynamoDbRenderer emits bespoke AttributeValue; suppress defau…
sbaluja Aug 27, 2026
52d3bff
Smithy: test ModelGenerator suppresses default AttributeValue render …
sbaluja Aug 27, 2026
2c2660d
Smithy: move DynamoDB AttributeValue suppression into a service-level…
sbaluja Aug 27, 2026
911da25
OperationContextParamsTrait handling and JmesPath parsing
sbaluja Aug 27, 2026
665c5b6
Smithy: scaffold S3Transforms and register in ModelCodegenPlugin
sbaluja Aug 28, 2026
54352dc
Smithy: S3Transforms renames CopyObjectResult to CopyObjectResultDetails
sbaluja Aug 28, 2026
46e87f0
Smithy: remove dead ShapeUtil collision-resolution helpers (folded in…
sbaluja Aug 28, 2026
fe84821
Smithy: S3Transforms adds Expires/ExpiresString backward-compat member
sbaluja Aug 28, 2026
56a733b
Smithy: scope S3 ExpiresString to outputs and retype Expires to times…
sbaluja Aug 28, 2026
00b805e
Smithy: S3Transforms injects GetObject Id2/RequestId header members
sbaluja Aug 28, 2026
a835e8e
Smithy: S3Transforms appends missing BucketLocationConstraint regions
sbaluja Aug 28, 2026
d78656f
Smithy: S3Transforms normalizes ReplicationStatus COMPLETE to COMPLETED
sbaluja Aug 28, 2026
6bb76ee
Smithy: record S3 serde-phased customizations as deferred parity deltas
sbaluja Aug 28, 2026
a28c2f3
Smithy: S3Transforms injects customizedAccessLogTag request member
sbaluja Aug 28, 2026
e198be9
Smithy: S3ControlTransforms adds top-level HostId to result classes
sbaluja Aug 28, 2026
b3ddae7
Smithy: fix S3 byte-parity — CopyObjectResult member rename, GetObjec…
sbaluja Aug 28, 2026
673e571
Smithy: S3Transforms invert ExpiresString guard and add Unit-input guard
sbaluja Aug 28, 2026
e8ba45f
Fix event stream dead code generation (unions, empty events)
sbaluja Aug 31, 2026
c4991fa
Smithy: restore S3 request AddQueryStringParameters and HasEmbeddedEr…
sbaluja Aug 31, 2026
1ddfb2d
Smithy: emit real (constant) HasEmbeddedError body instead of stub
sbaluja Aug 31, 2026
d1b2f2e
Smithy: S3Transforms retypes PartNumberMarker/NextPartNumberMarker ba…
sbaluja Aug 31, 2026
47eeef6
Smithy: S3Transforms ports IsStreaming override and checksum-member s…
sbaluja Aug 31, 2026
1affeec
Query string parameters and Request specific headers parity
sbaluja Sep 1, 2026
40ad6dc
glacier customizations and code cleanup
sbaluja Sep 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -64,54 +64,6 @@ public class ShapeUtil {
"cloudfront", "2020_05_31"
);

/**
* Hardcoded shape rename collision resolutions from C2J.
* These shapes had name collisions with operation result wrappers in C2J
* and were given specific alternative names.
* Map: service-name -> Map of original-shape-name -> resolved-name
*/
private static final Map<String, Map<String, String>> HARDCODED_COLLISION_RESOLUTIONS = Map.of(
"s3", Map.of("CopyObjectResult", "CopyObjectResultDetails"),
"accessanalyzer", Map.of("GeneratedPolicyResult", "GeneratedPolicyResults"),
"cloudsearchdomain", Map.of("SearchResult", "SearchResultDetails")
);

/**
* S3 shapes that exist in C2J but not in Smithy.
* These must be synthetically injected into the model before generation.
*/
public static final Map<String, Set<String>> C2J_ONLY_SHAPES = Map.of(
"s3", Set.of(
"CopyObjectResultDetails", "SelectObjectContentEventStreamUnmarshallerError",
"CloudFunctionConfiguration", "QueueConfigurationDeprecated",
"TopicConfigurationDeprecated", "NotificationConfigurationDeprecated",
"RequestPaymentConfiguration", "PutObjectLockConfigurationRequestAlias",
"GetObjectLockConfigurationResultAlias", "ObjectLockConfigurationAlias",
"ObjectLockRuleAlias", "DefaultRetentionAlias", "ObjectLockRetentionAlias"
)
);

/**
* Returns the hardcoded collision resolution for a shape, if one exists.
*/
public static Optional<String> getHardcodedResolution(String smithyServiceName, String shapeName) {
Map<String, String> serviceResolutions = HARDCODED_COLLISION_RESOLUTIONS.get(smithyServiceName);
if (serviceResolutions == null) return Optional.empty();
return Optional.ofNullable(serviceResolutions.get(shapeName));
}

/**
* Returns the C++ class name for a shape, applying collision renames and numeric prefix rules.
*/
public static String getShapeCppName(String shapeName, String smithyServiceName) {
Optional<String> resolved = getHardcodedResolution(smithyServiceName, shapeName);
if (resolved.isPresent()) return resolved.get();
if (!shapeName.isEmpty() && Character.isDigit(shapeName.charAt(0))) {
return "The" + shapeName;
}
return shapeName;
}

/**
* C2J/Smithy model mismatches: tokens that are integers in C2J but strings in Smithy.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,24 +275,10 @@ public static List<String> getIncludesForShape(Shape structureShape, Model model
}
} else {
addMemberInclude(includes, target, selfId, model, projectName);
// For list/map, also include the element/key/value types
if (target.isListShape()) {
ListShape list = target.asListShape().get();
addMemberInclude(includes, model.expectShape(list.getMember().getTarget()),
selfId, model, projectName);
}
if (target.isMapShape()) {
MapShape map = target.asMapShape().get();
addMemberInclude(includes, model.expectShape(map.getKey().getTarget()),
selfId, model, projectName);
addMemberInclude(includes, model.expectShape(map.getValue().getTarget()),
selfId, model, projectName);
}
// A @sparse list/map wraps its element/value in Aws::Crt::Optional, declared in
// <aws/crt/Optional.h>. Matches C2J's generated SparseNullsOperationRequest.h.
if ((target.isListShape() || target.isMapShape()) && target.hasTrait(SparseTrait.class)) {
includes.add("<aws/crt/Optional.h>");
}
// For list/map, recursively include every nested element/key/value type so leaf
// struct/enum headers reach the surface even through nested containers (e.g.
// apigateway Deployment.apiSummary: Map<String, Map<String, MethodSnapshot>>).
addContainerIncludes(includes, target, selfId, model, projectName);
}
// @idempotencyToken members are brace-initialized with
// Aws::Utils::UUID::PseudoRandomUUID(), which requires UUID.h. Matches C2J
Expand All @@ -316,6 +302,39 @@ private static void addMemberInclude(Set<String> includes, Shape shape, ShapeId
}
}

/**
* Recursively adds member-type includes for every nested element/key/value of a list or map
* shape. Recursion only descends through further list/map shapes and stops at
* structures/enums/scalars, so it is bounded by the container-nesting depth (no infinite
* recursion). {@code addMemberInclude} remains a no-op for container/scalar shapes without
* their own header. This lets a member typed, e.g., {@code Map<String, Map<String, Leaf>>}
* reach {@code Leaf}'s header, matching C2J's recursive unwrap.
*
* <p>The {@code @sparse}-&gt;{@code <aws/crt/Optional.h>} handling fires at each nested
* container level that is sparse, matching C2J's generated headers.
*/
private static void addContainerIncludes(Set<String> includes, Shape target, ShapeId selfId,
Model model, String projectName) {
if (target.isListShape()) {
Shape elem = model.expectShape(target.asListShape().get().getMember().getTarget());
addMemberInclude(includes, elem, selfId, model, projectName);
addContainerIncludes(includes, elem, selfId, model, projectName);
} else if (target.isMapShape()) {
MapShape map = target.asMapShape().get();
Shape key = model.expectShape(map.getKey().getTarget());
Shape value = model.expectShape(map.getValue().getTarget());
addMemberInclude(includes, key, selfId, model, projectName);
addMemberInclude(includes, value, selfId, model, projectName);
addContainerIncludes(includes, key, selfId, model, projectName);
addContainerIncludes(includes, value, selfId, model, projectName);
}
// A @sparse list/map wraps its element/value in Aws::Crt::Optional, declared in
// <aws/crt/Optional.h>. Matches C2J's generated SparseNullsOperationRequest.h.
if ((target.isListShape() || target.isMapShape()) && target.hasTrait(SparseTrait.class)) {
includes.add("<aws/crt/Optional.h>");
}
}

/**
* Returns the sorted C++ class names of every direct member whose target forms a reference
* cycle with {@code structureShape} (see {@link #isRecursiveStructMember}). These are stored
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -50,6 +51,20 @@ public static void renderHeader(CppWriter writer, Shape enumShape, String servic
writer.write("#include <aws/$1L/$2L_EXPORTS.h>",
projectName, serviceName);
writer.write("");

// Windows defines some enum values as preprocessor macros (e.g. EC2's `interface` via
// <combaseapi.h>). Undefine them so the generated enum constant compiles, matching C2J's
// ModelEnumHeader.vm predefined-symbol guard.
List<String> windowsMacros = predefinedWindowsSymbols(serviceName, values);
if (!windowsMacros.isEmpty()) {
for (String macro : windowsMacros) {
writer.write("#if defined(_WIN32) && defined($L)", macro);
writer.write("#undef $L", macro);
writer.write("#endif");
}
writer.write("");
}

writer.write("namespace Aws {");
writer.write("namespace $L {", serviceName);
writer.write("namespace Model {");
Expand Down Expand Up @@ -225,6 +240,34 @@ private static List<String> getEnumWireValues(Shape enumShape) {
"STATIC", "T_CHAR", "DOMAIN", "OVERFLOW", "WINDOWS"
);

/**
* Per-service enum constant names that collide with a Windows preprocessor macro and must be
* {@code #undef}'d in the enum header. Keyed by C++ service namespace, mirroring C2J
* PlatformAndKeywordSanitizer.PREDEFINED_SYMBOLS_MAPPING.
*/
private static final Map<String, Set<String>> PREDEFINED_WINDOWS_SYMBOLS = Map.of(
"DynamoDB", Set.of("IN"),
"EC2", Set.of("interface"),
"S3Crt", Set.of("IGNORE")
);

/**
* Returns, in enum-declaration order, the sanitized enum constant names of {@code values} that
* collide with a Windows macro for {@code serviceNamespace} (see
* {@link #PREDEFINED_WINDOWS_SYMBOLS}). Empty when the service has no such symbols.
*
* @param serviceNamespace the C++ service namespace (e.g., "EC2")
* @param values the sanitized enum constant names in declaration order
* @return the subset needing a {@code #undef} guard, preserving declaration order
*/
static List<String> predefinedWindowsSymbols(String serviceNamespace, List<String> values) {
Set<String> symbols = PREDEFINED_WINDOWS_SYMBOLS.get(serviceNamespace);
if (symbols == null) {
return List.of();
}
return values.stream().filter(symbols::contains).collect(Collectors.toList());
}

/**
* Sanitizes an enum wire value into a valid C++ identifier, matching C2J
* PlatformAndKeywordSanitizer.fixEnumValue() behavior.
Expand Down
Loading
Loading