2222import static software .amazon .awssdk .codegen .internal .Utils .isScalar ;
2323
2424import java .util .Collections ;
25- import java .util .HashSet ;
2625import java .util .List ;
2726import java .util .Map ;
2827import java .util .Optional ;
29- import java .util .Set ;
3028import software .amazon .awssdk .codegen .internal .TypeUtils ;
3129import software .amazon .awssdk .codegen .model .config .customization .CustomizationConfig ;
3230import software .amazon .awssdk .codegen .model .intermediate .EnumModel ;
3836import software .amazon .awssdk .codegen .model .intermediate .ReturnTypeModel ;
3937import software .amazon .awssdk .codegen .model .intermediate .ShapeModel ;
4038import software .amazon .awssdk .codegen .model .intermediate .VariableModel ;
41- import software .amazon .awssdk .codegen .model .service .ErrorMap ;
4239import software .amazon .awssdk .codegen .model .service .Location ;
4340import software .amazon .awssdk .codegen .model .service .Member ;
4441import software .amazon .awssdk .codegen .model .service .Operation ;
@@ -57,7 +54,6 @@ abstract class AddShapes {
5754
5855 private final IntermediateModelBuilder builder ;
5956 private final NamingStrategy namingStrategy ;
60- private Set <Shape > directOperationShapes ;
6157
6258 AddShapes (IntermediateModelBuilder builder ) {
6359 this .builder = builder ;
@@ -315,10 +311,9 @@ private ParameterHttpMapping generateParameterHttpMapping(Shape parentShape,
315311
316312 ParameterHttpMapping mapping = new ParameterHttpMapping ();
317313
314+ // Per the Smithy spec, HTTP binding traits are only honored on specific shape types:
318315 // https://smithy.io/2.0/spec/http-bindings.html
319- Location location = isDirectOperationShape (parentShape , allC2jShapes )
320- ? Location .forValue (member .getLocation ())
321- : null ;
316+ Location location = resolveLocation (parentShape , member , allC2jShapes );
322317
323318 Shape memberShape = allC2jShapes .get (member .getShape ());
324319 mapping .withLocation (location )
@@ -332,24 +327,43 @@ private ParameterHttpMapping generateParameterHttpMapping(Shape parentShape,
332327 return mapping ;
333328 }
334329
335- private boolean isDirectOperationShape (Shape parentShape , Map <String , Shape > allC2jShapes ) {
336- if ( directOperationShapes == null ) {
337- directOperationShapes = new HashSet <>();
338- for ( Operation operation : builder . getService (). getOperations (). values ()) {
339- if ( operation . getInput () != null ) {
340- directOperationShapes . add ( allC2jShapes . get ( operation . getInput (). getShape ()));
341- }
342- if ( operation . getOutput () != null ) {
343- directOperationShapes . add ( allC2jShapes . get ( operation . getOutput (). getShape ())) ;
344- }
345- if ( operation . getErrors () != null ) {
346- for ( ErrorMap error : operation . getErrors ()) {
347- directOperationShapes . add ( allC2jShapes . get ( error . getShape ()));
348- }
349- }
350- }
330+ private Location resolveLocation (Shape parentShape , Member member , Map <String , Shape > allC2jShapes ) {
331+ Location location = Location . forValue ( member . getLocation ());
332+ if ( location == null ) {
333+ return null ;
334+ }
335+ switch ( location ) {
336+ case URI :
337+ case QUERY_STRING :
338+ return isDirectInputShape ( parentShape , allC2jShapes ) ? location : null ;
339+ case HEADER :
340+ case HEADERS :
341+ return isDirectOperationShape ( parentShape , allC2jShapes ) ? location : null ;
342+ case STATUS_CODE :
343+ return isDirectOutputShape ( parentShape , allC2jShapes ) ? location : null ;
344+ default :
345+ return location ;
351346 }
352- return directOperationShapes .contains (parentShape );
347+ }
348+
349+ private boolean isDirectInputShape (Shape shape , Map <String , Shape > allC2jShapes ) {
350+ return builder .getService ().getOperations ().values ().stream ()
351+ .filter (o -> o .getInput () != null )
352+ .anyMatch (o -> allC2jShapes .get (o .getInput ().getShape ()).equals (shape ));
353+ }
354+
355+ private boolean isDirectOutputShape (Shape shape , Map <String , Shape > allC2jShapes ) {
356+ return builder .getService ().getOperations ().values ().stream ()
357+ .filter (o -> o .getOutput () != null )
358+ .anyMatch (o -> allC2jShapes .get (o .getOutput ().getShape ()).equals (shape ));
359+ }
360+
361+ private boolean isDirectOperationShape (Shape shape , Map <String , Shape > allC2jShapes ) {
362+ return builder .getService ().getOperations ().values ().stream ()
363+ .anyMatch (o -> (o .getInput () != null && allC2jShapes .get (o .getInput ().getShape ()).equals (shape ))
364+ || (o .getOutput () != null && allC2jShapes .get (o .getOutput ().getShape ()).equals (shape ))
365+ || (o .getErrors () != null && o .getErrors ().stream ()
366+ .anyMatch (e -> allC2jShapes .get (e .getShape ()).equals (shape ))));
353367 }
354368
355369 private boolean isFlattened (Member member , Shape memberShape ) {
@@ -407,8 +421,8 @@ private Optional<String> findRequestUri(Shape parentShape, Map<String, Shape> al
407421 .map (Map .Entry ::getKey )
408422 .findFirst ()
409423 .orElseThrow (() -> new IllegalStateException ("Shape not found in model: " + parentShape ));
410- String detailMsg = "Could not find request URI for input shape '" + shapeName
411- + "'. No operation was found that references this shape as its input ." ;
424+ String detailMsg = "Operation referencing input shape '" + shapeName
425+ + "' has no requestUri configured in its HTTP binding ." ;
412426 ValidationEntry entry =
413427 new ValidationEntry ().withErrorId (ValidationErrorId .REQUEST_URI_NOT_FOUND )
414428 .withDetailMessage (detailMsg )
0 commit comments