Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions .changes/next-release/bugfix-AWSSDKforJavav2-40c3de6.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "bugfix",
"category": "AWS SDK for Java v2",
"contributor": "",
"description": "Eliminate per-operation lambdas for endpoint and auth scheme resolution in generated clients, permanently fixing constant pool overflow for large services like EC2 Internal."
}
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,7 @@ protected void addAdditionalMethods(TypeSpec.Builder type) {
.addMethod(protocolSpec.initProtocolFactory(model))
.addMethod(resolveMetricPublishersMethod())
.addMethod(ClientClassUtils.resolveAuthSchemeOptionsMethod(authSchemeSpecUtils, endpointRulesSpecUtils))
.addMethod(ClientClassUtils.resolveEndpointMethod(authSchemeSpecUtils, endpointRulesSpecUtils))
.addMethod(ClientClassUtils.authSchemeResolverFactoryMethod())
.addMethod(ClientClassUtils.endpointResolverFactoryMethod());
.addMethod(ClientClassUtils.resolveEndpointMethod(authSchemeSpecUtils, endpointRulesSpecUtils));

type.addMethod(ClientClassUtils.updateRetryStrategyClientConfigurationMethod());
type.addMethod(updateSdkClientConfigurationMethod(configurationUtils.serviceClientConfigurationBuilderClassName(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,12 @@
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
import software.amazon.awssdk.core.client.config.SdkClientConfiguration;
import software.amazon.awssdk.core.client.config.SdkClientOption;
import software.amazon.awssdk.core.endpoint.EndpointResolver;
import software.amazon.awssdk.core.exception.SdkClientException;
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute;
import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute;
import software.amazon.awssdk.core.retry.RetryMode;
import software.amazon.awssdk.core.signer.Signer;
import software.amazon.awssdk.core.spi.identity.AuthSchemeOptionsResolver;
import software.amazon.awssdk.endpoints.Endpoint;
import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption;
import software.amazon.awssdk.retries.api.RetryStrategy;
Expand Down Expand Up @@ -368,11 +367,13 @@ static MethodSpec resolveAuthSchemeOptionsMethod(AuthSchemeSpecUtils authSchemeS
.addModifiers(PRIVATE)
.returns(ParameterizedTypeName.get(ClassName.get(List.class), ClassName.get(AuthSchemeOption.class)))
.addParameter(SdkRequest.class, "request")
.addParameter(String.class, "operationName")
.addParameter(SdkClientConfiguration.class, "clientConfiguration");
.addParameter(ExecutionAttributes.class, "executionAttributes");

ClassName providerInterface = authSchemeSpecUtils.providerInterfaceName();

builder.addStatement("String operationName = executionAttributes.getAttribute($T.OPERATION_NAME)",
SdkExecutionAttribute.class);

// Check for request-level authSchemeProvider override
builder.addStatement("$T requestAuthSchemeProvider = request.overrideConfiguration()"
+ ".flatMap(c -> c.authSchemeProvider())"
Expand All @@ -383,8 +384,9 @@ static MethodSpec resolveAuthSchemeOptionsMethod(AuthSchemeSpecUtils authSchemeS
builder.addStatement("$T authSchemeProvider = requestAuthSchemeProvider != null "
+ "? requestAuthSchemeProvider "
+ ": $T.isInstanceOf($T.class, "
+ "clientConfiguration.option($T.AUTH_SCHEME_PROVIDER), $S)",
providerInterface, Validate.class, providerInterface, SdkClientOption.class,
+ "executionAttributes.getAttribute($T.AUTH_SCHEME_RESOLVER), $S)",
providerInterface, Validate.class, providerInterface,
SdkInternalExecutionAttribute.class,
"Expected an instance of " + authSchemeSpecUtils.providerInterfaceName().simpleName());

if (authSchemeSpecUtils.useEndpointBasedAuthProvider()) {
Expand All @@ -395,8 +397,8 @@ static MethodSpec resolveAuthSchemeOptionsMethod(AuthSchemeSpecUtils authSchemeS

if (endpointRulesSpecUtils.isS3()) {
ClassName sdkIdentityProperty = ClassName.get("software.amazon.awssdk.core.identity", "SdkIdentityProperty");
builder.addStatement("$T sdkClient = clientConfiguration.option($T.SDK_CLIENT)",
SdkClient.class, SdkClientOption.class);
builder.addStatement("$T sdkClient = executionAttributes.getAttribute($T.SDK_CLIENT)",
SdkClient.class, SdkInternalExecutionAttribute.class);
builder.addStatement("return options.stream().map(o -> o.toBuilder()"
+ ".putIdentityProperty($T.SDK_CLIENT, sdkClient).build())"
+ ".collect($T.toList())",
Expand All @@ -411,19 +413,21 @@ static MethodSpec resolveAuthSchemeOptionsMethod(AuthSchemeSpecUtils authSchemeS
private static void addSimpleAuthSchemeResolution(MethodSpec.Builder builder,
AuthSchemeSpecUtils authSchemeSpecUtils) {
ClassName paramsInterface = authSchemeSpecUtils.parametersInterfaceName();
ClassName awsClientOption = ClassName.get("software.amazon.awssdk.awscore.client.config", "AwsClientOption");
ClassName awsExecutionAttribute = ClassName.get("software.amazon.awssdk.awscore", "AwsExecutionAttribute");

builder.addStatement("$T.Builder paramsBuilder = $T.builder().operation(operationName)",
paramsInterface, paramsInterface);

if (authSchemeSpecUtils.usesSigV4()) {
builder.addStatement("paramsBuilder.region(clientConfiguration.option($T.AWS_REGION))", awsClientOption);
builder.addStatement("paramsBuilder.region(executionAttributes.getAttribute($T.AWS_REGION))",
awsExecutionAttribute);
}

if (authSchemeSpecUtils.hasSigV4aSupport()) {
ClassName regionSet = ClassName.get("software.amazon.awssdk.http.auth.aws.signer", "RegionSet");
builder.addStatement("$T<String> sigv4aRegionSet = clientConfiguration.option($T.AWS_SIGV4A_SIGNING_REGION_SET)",
ClassName.get(Set.class), awsClientOption);
builder.addStatement("$T<String> sigv4aRegionSet = executionAttributes"
+ ".getAttribute($T.AWS_SIGV4A_SIGNING_REGION_SET)",
ClassName.get(Set.class), awsExecutionAttribute);
builder.beginControlFlow("if (!$T.isNullOrEmpty(sigv4aRegionSet))", CollectionUtils.class);
builder.addStatement("paramsBuilder.regionSet($T.create(sigv4aRegionSet))", regionSet);
builder.endControlFlow();
Expand All @@ -437,32 +441,12 @@ private static void addEndpointBasedAuthSchemeResolution(MethodSpec.Builder buil
AuthSchemeSpecUtils authSchemeSpecUtils,
EndpointRulesSpecUtils endpointRulesSpecUtils) {
ClassName paramsInterface = authSchemeSpecUtils.parametersInterfaceName();
ClassName awsClientOption = ClassName.get("software.amazon.awssdk.awscore.client.config", "AwsClientOption");
ClassName awsExecutionAttribute = ClassName.get("software.amazon.awssdk.awscore", "AwsExecutionAttribute");
ClassName endpointParamsClass = endpointRulesSpecUtils.parametersClassName();
ClassName endpointResolverUtils = endpointRulesSpecUtils.endpointResolverUtilsName();
ClassName executionAttributesClass = ClassName.get("software.amazon.awssdk.core.interceptor", "ExecutionAttributes");
ClassName awsExecutionAttribute = ClassName.get("software.amazon.awssdk.awscore", "AwsExecutionAttribute");
ClassName sdkExecutionAttribute = ClassName.get("software.amazon.awssdk.core.interceptor", "SdkExecutionAttribute");
ClassName sdkInternalExecutionAttribute = ClassName.get("software.amazon.awssdk.core.interceptor",
"SdkInternalExecutionAttribute");

builder.addStatement("$T executionAttributes = new $T()", executionAttributesClass, executionAttributesClass);
builder.addStatement("executionAttributes.putAttribute($T.AWS_REGION, clientConfiguration.option($T.AWS_REGION))",
awsExecutionAttribute, awsClientOption);
builder.addStatement("executionAttributes.putAttribute($T.DUALSTACK_ENDPOINT_ENABLED, "
+ "clientConfiguration.option($T.DUALSTACK_ENDPOINT_ENABLED))",
awsExecutionAttribute, awsClientOption);
builder.addStatement("executionAttributes.putAttribute($T.FIPS_ENDPOINT_ENABLED, "
+ "clientConfiguration.option($T.FIPS_ENDPOINT_ENABLED))",
awsExecutionAttribute, awsClientOption);
builder.addStatement("executionAttributes.putAttribute($T.OPERATION_NAME, operationName)", sdkExecutionAttribute);
builder.addStatement("executionAttributes.putAttribute($T.CLIENT_ENDPOINT_PROVIDER, "
+ "clientConfiguration.option($T.CLIENT_ENDPOINT_PROVIDER))",
sdkInternalExecutionAttribute, SdkClientOption.class);
builder.addStatement("executionAttributes.putAttribute($T.CLIENT_CONTEXT_PARAMS, "
+ "clientConfiguration.option($T.CLIENT_CONTEXT_PARAMS))",
sdkInternalExecutionAttribute, SdkClientOption.class);

builder.addStatement("$T endpointParams = $T.ruleParams(request, executionAttributes)",
endpointParamsClass, endpointResolverUtils);

Expand All @@ -481,13 +465,15 @@ private static void addEndpointBasedAuthSchemeResolution(MethodSpec.Builder buil
builder.addStatement("paramsBuilder.operation(operationName)");

if (authSchemeSpecUtils.usesSigV4() && !regionIncluded) {
builder.addStatement("paramsBuilder.region(clientConfiguration.option($T.AWS_REGION))", awsClientOption);
builder.addStatement("paramsBuilder.region(executionAttributes.getAttribute($T.AWS_REGION))",
awsExecutionAttribute);
}

if (authSchemeSpecUtils.hasSigV4aSupport()) {
ClassName regionSet = ClassName.get("software.amazon.awssdk.http.auth.aws.signer", "RegionSet");
builder.addStatement("$T<String> sigv4aRegionSet = clientConfiguration.option($T.AWS_SIGV4A_SIGNING_REGION_SET)",
ClassName.get(Set.class), awsClientOption);
builder.addStatement("$T<String> sigv4aRegionSet = executionAttributes"
+ ".getAttribute($T.AWS_SIGV4A_SIGNING_REGION_SET)",
ClassName.get(Set.class), awsExecutionAttribute);
builder.beginControlFlow("if (!$T.isNullOrEmpty(sigv4aRegionSet))", CollectionUtils.class);
builder.addStatement("paramsBuilder.regionSet($T.create(sigv4aRegionSet))", regionSet);
builder.endControlFlow();
Expand All @@ -497,8 +483,10 @@ private static void addEndpointBasedAuthSchemeResolution(MethodSpec.Builder buil
ClassName endpointProviderInterface = endpointRulesSpecUtils.providerInterfaceName();

builder.beginControlFlow("if (paramsBuilder instanceof $T)", paramsBuilderClass);
builder.addStatement("$T endpointProvider = clientConfiguration.option($T.ENDPOINT_PROVIDER)",
ClassName.get("software.amazon.awssdk.endpoints", "EndpointProvider"), SdkClientOption.class);
builder.addStatement("$T endpointProvider = ($T) executionAttributes.getAttribute($T.ENDPOINT_PROVIDER)",
ClassName.get("software.amazon.awssdk.endpoints", "EndpointProvider"),
ClassName.get("software.amazon.awssdk.endpoints", "EndpointProvider"),
sdkInternalExecutionAttribute);
builder.beginControlFlow("if (endpointProvider instanceof $T)", endpointProviderInterface);
builder.addStatement("(($T) paramsBuilder).endpointProvider(($T) endpointProvider)",
paramsBuilderClass, endpointProviderInterface);
Expand All @@ -509,39 +497,6 @@ private static void addEndpointBasedAuthSchemeResolution(MethodSpec.Builder buil
List.class, AuthSchemeOption.class);
}

/**
* Generates a factory method that creates an {@code AuthSchemeOptionsResolver} for a given operation name.
* This avoids creating a new lambda per operation in the generated client class, which reduces constant pool
* pressure for services with a large number of operations (e.g., EC2).
*/
static MethodSpec authSchemeResolverFactoryMethod() {
ClassName authSchemeOptionsResolver = ClassName.get(AuthSchemeOptionsResolver.class);

return MethodSpec.methodBuilder("authSchemeResolver")
.addModifiers(PRIVATE)
.returns(authSchemeOptionsResolver)
.addParameter(String.class, "operationName")
.addParameter(SdkClientConfiguration.class, "clientConfiguration")
.addStatement("return r -> resolveAuthSchemeOptions(r, operationName, clientConfiguration)")
.build();
}

/**
* Generates a factory method that creates an {@code EndpointResolver} for a given operation name.
* This avoids creating a new lambda per operation in the generated client class, which reduces constant pool
* pressure for services with a large number of operations (e.g., EC2).
*/
static MethodSpec endpointResolverFactoryMethod() {
ClassName endpointResolver = ClassName.get(EndpointResolver.class);

return MethodSpec.methodBuilder("endpointResolver")
.addModifiers(PRIVATE)
.returns(endpointResolver)
.addParameter(String.class, "operationName")
.addStatement("return (r, a) -> resolveEndpoint(r, a, operationName)")
.build();
}

static MethodSpec resolveEndpointMethod(AuthSchemeSpecUtils authSchemeSpecUtils,
EndpointRulesSpecUtils endpointRulesSpecUtils) {
ClassName utilsClass = endpointRulesSpecUtils.endpointResolverUtilsName();
Expand All @@ -555,8 +510,9 @@ static MethodSpec resolveEndpointMethod(AuthSchemeSpecUtils authSchemeSpecUtils,
.addModifiers(PRIVATE)
.returns(Endpoint.class)
.addParameter(SdkRequest.class, "request")
.addParameter(ExecutionAttributes.class, "executionAttributes")
.addParameter(String.class, "operationName");
.addParameter(ExecutionAttributes.class, "executionAttributes");

b.addStatement("String operationName = executionAttributes.getAttribute($T.OPERATION_NAME)", SdkExecutionAttribute.class);

b.addStatement("$1T provider = ($1T) executionAttributes.getAttribute($2T.ENDPOINT_PROVIDER)",
providerInterface, SdkInternalExecutionAttribute.class);
Expand Down Expand Up @@ -623,4 +579,5 @@ static MethodSpec resolveEndpointMethod(AuthSchemeSpecUtils authSchemeSpecUtils,

return b.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,7 @@ protected void addAdditionalMethods(TypeSpec.Builder type) {
.addMethods(protocolSpec.additionalMethods())
.addMethod(resolveMetricPublishersMethod())
.addMethod(ClientClassUtils.resolveAuthSchemeOptionsMethod(authSchemeSpecUtils, endpointRulesSpecUtils))
.addMethod(ClientClassUtils.resolveEndpointMethod(authSchemeSpecUtils, endpointRulesSpecUtils))
.addMethod(ClientClassUtils.authSchemeResolverFactoryMethod())
.addMethod(ClientClassUtils.endpointResolverFactoryMethod());
.addMethod(ClientClassUtils.resolveEndpointMethod(authSchemeSpecUtils, endpointRulesSpecUtils));

protocolSpec.createErrorResponseHandler().ifPresent(type::addMethod);
type.addMethod(ClientClassUtils.updateRetryStrategyClientConfigurationMethod());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,10 +224,8 @@ public CodeBlock executionHandler(OperationModel opModel) {
.add(".withRequestConfiguration(clientConfiguration)")
.add(".withInput($L)\n", opModel.getInput().getVariableName())
.add(".withMetricCollector(apiCallMetricCollector)\n")
.add(".withAuthSchemeOptionsResolver(authSchemeResolver($S, clientConfiguration))\n",
opModel.getOperationName())
.add(".withEndpointResolver(endpointResolver($S))\n",
opModel.getOperationName())
.add(".withAuthSchemeOptionsResolver(this::resolveAuthSchemeOptions)\n")
.add(".withEndpointResolver(this::resolveEndpoint)\n")
.add(HttpChecksumRequiredTrait.putHttpChecksumAttribute(opModel))
.add(HttpChecksumTrait.create(opModel));

Expand Down Expand Up @@ -302,10 +300,8 @@ public CodeBlock asyncExecutionHandler(IntermediateModel intermediateModel, Oper
.add(".withErrorResponseHandler(errorResponseHandler)\n")
.add(".withRequestConfiguration(clientConfiguration)")
.add(".withMetricCollector(apiCallMetricCollector)\n")
.add(".withAuthSchemeOptionsResolver(authSchemeResolver($S, clientConfiguration))\n",
opModel.getOperationName())
.add(".withEndpointResolver(endpointResolver($S))\n",
opModel.getOperationName())
.add(".withAuthSchemeOptionsResolver(this::resolveAuthSchemeOptions)\n")
.add(".withEndpointResolver(this::resolveEndpoint)\n")
.add(hostPrefixExpression(opModel))
.add(discoveredEndpoint(opModel))
.add(credentialType(opModel, model))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,8 @@ public CodeBlock executionHandler(OperationModel opModel) {
.add(".withRequestConfiguration(clientConfiguration)")
.add(".withInput($L)", opModel.getInput().getVariableName())
.add(".withMetricCollector(apiCallMetricCollector)")
.add(".withAuthSchemeOptionsResolver(authSchemeResolver($S, clientConfiguration))\n",
opModel.getOperationName())
.add(".withEndpointResolver(endpointResolver($S))\n",
opModel.getOperationName())
.add(".withAuthSchemeOptionsResolver(this::resolveAuthSchemeOptions)\n")
.add(".withEndpointResolver(this::resolveEndpoint)\n")
.add(HttpChecksumRequiredTrait.putHttpChecksumAttribute(opModel))
.add(HttpChecksumTrait.create(opModel));

Expand Down Expand Up @@ -159,10 +157,8 @@ public CodeBlock asyncExecutionHandler(IntermediateModel intermediateModel, Oper
.add(credentialType(opModel, intermediateModel))
.add(".withRequestConfiguration(clientConfiguration)")
.add(".withMetricCollector(apiCallMetricCollector)\n")
.add(".withAuthSchemeOptionsResolver(authSchemeResolver($S, clientConfiguration))\n",
opModel.getOperationName())
.add(".withEndpointResolver(endpointResolver($S))\n",
opModel.getOperationName())
.add(".withAuthSchemeOptionsResolver(this::resolveAuthSchemeOptions)\n")
.add(".withEndpointResolver(this::resolveEndpoint)\n")
.add(HttpChecksumRequiredTrait.putHttpChecksumAttribute(opModel))
.add(HttpChecksumTrait.create(opModel));

Expand Down
Loading
Loading