From d375306c652f1cf7405bdddc0b34d1c05b7f125e Mon Sep 17 00:00:00 2001 From: Saranya Somepalli Date: Tue, 30 Jun 2026 15:47:00 -0700 Subject: [PATCH 1/4] Remove ServiceMetadata usage from AwsClientEndpointProvider in generated client builders --- .../poet/builder/BaseClientBuilderClass.java | 70 ++++++++++++++----- ...test-bearer-auth-client-builder-class.java | 49 +++++++++---- .../builder/test-client-builder-class.java | 49 +++++++++---- ...-client-builder-endpoints-auth-params.java | 51 ++++++++++---- ...lient-builder-internal-defaults-class.java | 49 +++++++++---- ...-composed-sync-default-client-builder.java | 49 +++++++++---- ...env-bearer-token-client-builder-class.java | 48 +++++++++---- .../test-h2-service-client-builder-class.java | 49 +++++++++---- ...dgeForH2-service-client-builder-class.java | 49 +++++++++---- ...ulti-auth-sigv4a-client-builder-class.java | 49 +++++++++---- ...test-no-auth-ops-client-builder-class.java | 49 +++++++++---- ...-no-auth-service-client-builder-class.java | 49 +++++++++---- .../test-query-client-builder-class.java | 51 ++++++++++---- .../endpoint/AwsClientEndpointProvider.java | 17 +++++ 14 files changed, 482 insertions(+), 196 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java index d3c37f92a367..5772aa2540a2 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java @@ -30,6 +30,7 @@ import com.squareup.javapoet.TypeSpec; import com.squareup.javapoet.TypeVariableName; import com.squareup.javapoet.WildcardTypeName; +import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -49,6 +50,7 @@ import software.amazon.awssdk.codegen.internal.Utils; import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; import software.amazon.awssdk.codegen.model.intermediate.OperationModel; +import software.amazon.awssdk.codegen.model.rules.endpoints.BuiltInParameter; import software.amazon.awssdk.codegen.model.service.ClientContextParam; import software.amazon.awssdk.codegen.poet.ClassSpec; import software.amazon.awssdk.codegen.poet.PoetExtension; @@ -86,7 +88,6 @@ import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; -import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.utils.AttributeMap; import software.amazon.awssdk.utils.CollectionUtils; import software.amazon.awssdk.utils.StringUtils; @@ -514,21 +515,53 @@ private MethodSpec finalizeServiceConfigurationMethod() { String serviceNameForSystemProperty = model.getNamingStrategy().getServiceNameForSystemProperties(); String serviceNameForProfileFile = model.getNamingStrategy().getServiceNameForProfileFile(); - builder.addCode("builder.lazyOptionIfAbsent($T.CLIENT_ENDPOINT_PROVIDER, c ->", SdkClientOption.class) - .addCode(" $T.builder()", AwsClientEndpointProvider.class) - .addCode(" .serviceEndpointOverrideEnvironmentVariable($S)", "AWS_ENDPOINT_URL_" + serviceNameForEnvVar) - .addCode(" .serviceEndpointOverrideSystemProperty($S)", "aws.endpointUrl" + serviceNameForSystemProperty) - .addCode(" .serviceProfileProperty($S)", serviceNameForProfileFile) - .addCode(" .serviceEndpointPrefix(serviceEndpointPrefix())") - .addCode(" .defaultProtocol($S)", "https") - .addCode(" .region(c.get($T.AWS_REGION))", AwsClientOption.class) - .addCode(" .profileFile(c.get($T.PROFILE_FILE_SUPPLIER))", SdkClientOption.class) - .addCode(" .profileName(c.get($T.PROFILE_NAME))", SdkClientOption.class) - .addCode(" .putAdvancedOption($T.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT,", ServiceMetadataAdvancedOption.class) - .addCode(" c.get($T.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT))", ServiceMetadataAdvancedOption.class) - .addCode(" .dualstackEnabled(c.get($T.DUALSTACK_ENDPOINT_ENABLED))", AwsClientOption.class) - .addCode(" .fipsEnabled(c.get($T.FIPS_ENDPOINT_ENABLED))", AwsClientOption.class) - .addCode(" .build());"); + builder.addCode("builder.lazyOptionIfAbsent($T.CLIENT_ENDPOINT_PROVIDER, c -> {\n", SdkClientOption.class) + .addCode(" $T<$T> endpointFromOverrides = $T.builder()\n", + Optional.class, ClassName.get("software.amazon.awssdk.core", "ClientEndpointProvider"), + AwsClientEndpointProvider.class) + .addCode(" .serviceEndpointOverrideEnvironmentVariable($S)\n", "AWS_ENDPOINT_URL_" + serviceNameForEnvVar) + .addCode(" .serviceEndpointOverrideSystemProperty($S)\n", "aws.endpointUrl" + serviceNameForSystemProperty) + .addCode(" .serviceProfileProperty($S)\n", serviceNameForProfileFile) + .addCode(" .profileFile(c.get($T.PROFILE_FILE_SUPPLIER))\n", SdkClientOption.class) + .addCode(" .profileName(c.get($T.PROFILE_NAME))\n", SdkClientOption.class) + .addCode(" .buildIfOverridePresent();\n") + .addCode(" if (endpointFromOverrides.isPresent()) {\n") + .addCode(" return endpointFromOverrides.get();\n") + .addCode(" }\n") + .addCode(" $T clientEndpointUri = null;\n", URI.class) + .addCode(" try {\n") + .addCode(" $T endpointParams = $T.builder()\n", + endpointRulesSpecUtils.parametersClassName(), endpointRulesSpecUtils.parametersClassName()) + .addCode(" .region(c.get($T.AWS_REGION))\n", AwsClientOption.class); + + if (hasBuiltIn(BuiltInParameter.AWS_USE_DUAL_STACK)) { + builder.addCode(" .useDualStack(c.get($T.DUALSTACK_ENDPOINT_ENABLED))\n", AwsClientOption.class); + } + if (hasBuiltIn(BuiltInParameter.AWS_USE_FIPS)) { + builder.addCode(" .useFips(c.get($T.FIPS_ENDPOINT_ENABLED))\n", AwsClientOption.class); + } + + builder.addCode(" .build();\n") + .addCode(" $T endpoint = $T.joinLikeSync(defaultEndpointProvider().resolveEndpoint(endpointParams));\n", + ClassName.get("software.amazon.awssdk.endpoints", "Endpoint"), + ClassName.get("software.amazon.awssdk.utils", "CompletableFutureUtils")) + .addCode(" clientEndpointUri = endpoint.url();\n") + .addCode(" } catch (Exception e) {\n") + .addCode(" // Resolution requires request-bound params; fallback to placeholder, resolved at request time.\n") + .addCode(" return $T.create($T.create($S), false);\n", + ClassName.get("software.amazon.awssdk.core", "ClientEndpointProvider"), + URI.class, "https://localhost") + .addCode(" }\n") + .addCode(" if (clientEndpointUri.getHost() == null) {\n") + .addCode(" throw $T.create(\"Configured region (\" + c.get($T.AWS_REGION)\n", + ClassName.get("software.amazon.awssdk.core.exception", "SdkClientException"), + AwsClientOption.class) + .addCode(" + \") resulted in an invalid URI: \" + clientEndpointUri\n") + .addCode(" + \". This is usually caused by an invalid region configuration.\");\n") + .addCode(" }\n") + .addCode(" return $T.create(clientEndpointUri, false);\n", + ClassName.get("software.amazon.awssdk.core", "ClientEndpointProvider")) + .addCode("});\n"); if (model.getMetadata().isJsonProtocol()) { builder.addStatement("builder.option($1T.ENABLE_FAST_UNMARSHALLER, true)", @@ -1051,6 +1084,11 @@ private boolean hasClientContextParams() { return clientContextParams != null && !clientContextParams.isEmpty(); } + private boolean hasBuiltIn(BuiltInParameter builtIn) { + return model.getEndpointRuleSetModel().getParameters().values().stream() + .anyMatch(p -> builtIn.equals(p.getBuiltInEnum())); + } + private boolean hasSdkClientContextParams() { return model.getCustomizationConfig() != null && model.getCustomizationConfig().getCustomClientContextParams() != null diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-bearer-auth-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-bearer-auth-client-builder-class.java index ee8f9a73d3e5..57e70c6b7864 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-bearer-auth-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-bearer-auth-client-builder-class.java @@ -1,10 +1,12 @@ package software.amazon.awssdk.services.json; +import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; @@ -15,13 +17,16 @@ import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.SdkPlugin; 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.exception.SdkClientException; import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; import software.amazon.awssdk.core.retry.RetryMode; +import software.amazon.awssdk.endpoints.Endpoint; import software.amazon.awssdk.http.auth.scheme.BearerAuthScheme; import software.amazon.awssdk.http.auth.scheme.NoAuthAuthScheme; import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme; @@ -29,15 +34,16 @@ import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; -import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeProvider; import software.amazon.awssdk.services.json.auth.scheme.internal.JsonAuthSchemeInterceptor; +import software.amazon.awssdk.services.json.endpoints.JsonEndpointParams; import software.amazon.awssdk.services.json.endpoints.JsonEndpointProvider; import software.amazon.awssdk.services.json.endpoints.internal.JsonRequestSetEndpointInterceptor; import software.amazon.awssdk.services.json.endpoints.internal.JsonResolveEndpointInterceptor; import software.amazon.awssdk.services.json.internal.JsonServiceClientConfigurationBuilder; import software.amazon.awssdk.utils.CollectionUtils; +import software.amazon.awssdk.utils.CompletableFutureUtils; import software.amazon.awssdk.utils.Validate; /** @@ -96,20 +102,33 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") - .serviceProfileProperty("json_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + c -> { + Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson").serviceProfileProperty("json_service") + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); + if (endpointFromOverrides.isPresent()) { + return endpointFromOverrides.get(); + } + URI clientEndpointUri = null; + try { + JsonEndpointParams endpointParams = JsonEndpointParams.builder() + .region(c.get(AwsClientOption.AWS_REGION)).build(); + Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( + endpointParams)); + clientEndpointUri = endpoint.url(); + } catch (Exception e) { + // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + return ClientEndpointProvider.create(URI.create("https://localhost"), false); + } + if (clientEndpointUri.getHost() == null) { + throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) + + ") resulted in an invalid URI: " + clientEndpointUri + + ". This is usually caused by an invalid region configuration."); + } + return ClientEndpointProvider.create(clientEndpointUri, false); + }); builder.option(SdkClientJsonProtocolAdvancedOption.ENABLE_FAST_UNMARSHALLER, true); return builder.build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-class.java index a0bdac67d04d..89afff11fc92 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-class.java @@ -1,9 +1,11 @@ package software.amazon.awssdk.services.json; +import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Consumer; import software.amazon.MyServiceHttpConfig; import software.amazon.MyServiceRetryPolicy; @@ -19,6 +21,7 @@ import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; import software.amazon.awssdk.codegen.poet.plugins.InternalTestPlugin1; import software.amazon.awssdk.codegen.poet.plugins.InternalTestPlugin2; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.checksums.RequestChecksumCalculation; import software.amazon.awssdk.core.checksums.RequestChecksumCalculationResolver; @@ -27,9 +30,11 @@ 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.exception.SdkClientException; import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; import software.amazon.awssdk.core.retry.RetryMode; +import software.amazon.awssdk.endpoints.Endpoint; import software.amazon.awssdk.http.auth.aws.scheme.AwsV4AuthScheme; import software.amazon.awssdk.http.auth.scheme.BearerAuthScheme; import software.amazon.awssdk.http.auth.scheme.NoAuthAuthScheme; @@ -38,17 +43,18 @@ import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; -import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeProvider; import software.amazon.awssdk.services.json.auth.scheme.internal.JsonAuthSchemeInterceptor; import software.amazon.awssdk.services.json.endpoints.JsonClientContextParams; +import software.amazon.awssdk.services.json.endpoints.JsonEndpointParams; import software.amazon.awssdk.services.json.endpoints.JsonEndpointProvider; import software.amazon.awssdk.services.json.endpoints.internal.JsonRequestSetEndpointInterceptor; import software.amazon.awssdk.services.json.endpoints.internal.JsonResolveEndpointInterceptor; import software.amazon.awssdk.services.json.internal.JsonServiceClientConfigurationBuilder; import software.amazon.awssdk.utils.AttributeMap; import software.amazon.awssdk.utils.CollectionUtils; +import software.amazon.awssdk.utils.CompletableFutureUtils; import software.amazon.awssdk.utils.Validate; /** @@ -192,20 +198,33 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(SdkClientOption.SERVICE_CONFIGURATION, finalServiceConfig); builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") - .serviceProfileProperty("json_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + c -> { + Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson").serviceProfileProperty("json_service") + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); + if (endpointFromOverrides.isPresent()) { + return endpointFromOverrides.get(); + } + URI clientEndpointUri = null; + try { + JsonEndpointParams endpointParams = JsonEndpointParams.builder() + .region(c.get(AwsClientOption.AWS_REGION)).build(); + Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( + endpointParams)); + clientEndpointUri = endpoint.url(); + } catch (Exception e) { + // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + return ClientEndpointProvider.create(URI.create("https://localhost"), false); + } + if (clientEndpointUri.getHost() == null) { + throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) + + ") resulted in an invalid URI: " + clientEndpointUri + + ". This is usually caused by an invalid region configuration."); + } + return ClientEndpointProvider.create(clientEndpointUri, false); + }); builder.option(SdkClientJsonProtocolAdvancedOption.ENABLE_FAST_UNMARSHALLER, true); SdkClientConfiguration clientConfig = config; builder.lazyOption(SdkClientOption.REQUEST_CHECKSUM_CALCULATION, c -> resolveRequestChecksumCalculation(clientConfig)); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-endpoints-auth-params.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-endpoints-auth-params.java index 360d3664eaad..9d3b7b0d5e8b 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-endpoints-auth-params.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-endpoints-auth-params.java @@ -1,10 +1,12 @@ package software.amazon.awssdk.services.query; +import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; @@ -17,6 +19,7 @@ import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointMode; import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointModeResolver; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.checksums.RequestChecksumCalculation; import software.amazon.awssdk.core.checksums.RequestChecksumCalculationResolver; @@ -25,9 +28,11 @@ 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.exception.SdkClientException; import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; import software.amazon.awssdk.core.retry.RetryMode; +import software.amazon.awssdk.endpoints.Endpoint; import software.amazon.awssdk.http.auth.aws.scheme.AwsV4AuthScheme; import software.amazon.awssdk.http.auth.aws.scheme.AwsV4aAuthScheme; import software.amazon.awssdk.http.auth.aws.signer.RegionSet; @@ -37,16 +42,17 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; -import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.query.auth.scheme.QueryAuthSchemeProvider; import software.amazon.awssdk.services.query.auth.scheme.internal.QueryAuthSchemeInterceptor; import software.amazon.awssdk.services.query.endpoints.QueryClientContextParams; +import software.amazon.awssdk.services.query.endpoints.QueryEndpointParams; import software.amazon.awssdk.services.query.endpoints.QueryEndpointProvider; import software.amazon.awssdk.services.query.endpoints.internal.QueryRequestSetEndpointInterceptor; import software.amazon.awssdk.services.query.endpoints.internal.QueryResolveEndpointInterceptor; import software.amazon.awssdk.services.query.internal.QueryServiceClientConfigurationBuilder; import software.amazon.awssdk.utils.CollectionUtils; +import software.amazon.awssdk.utils.CompletableFutureUtils; import software.amazon.awssdk.utils.Validate; /** @@ -111,20 +117,35 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(AwsClientOption.ACCOUNT_ID_ENDPOINT_MODE, resolveAccountIdEndpointMode(config)); builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_QUERY_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlQuery") - .serviceProfileProperty("query_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + c -> { + Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_QUERY_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlQuery") + .serviceProfileProperty("query_service").profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); + if (endpointFromOverrides.isPresent()) { + return endpointFromOverrides.get(); + } + URI clientEndpointUri = null; + try { + QueryEndpointParams endpointParams = QueryEndpointParams.builder() + .region(c.get(AwsClientOption.AWS_REGION)) + .useDualStack(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .useFips(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build(); + Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( + endpointParams)); + clientEndpointUri = endpoint.url(); + } catch (Exception e) { + // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + return ClientEndpointProvider.create(URI.create("https://localhost"), false); + } + if (clientEndpointUri.getHost() == null) { + throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) + + ") resulted in an invalid URI: " + clientEndpointUri + + ". This is usually caused by an invalid region configuration."); + } + return ClientEndpointProvider.create(clientEndpointUri, false); + }); SdkClientConfiguration clientConfig = config; builder.lazyOption(SdkClientOption.REQUEST_CHECKSUM_CALCULATION, c -> resolveRequestChecksumCalculation(clientConfig)); builder.lazyOption(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION, c -> resolveResponseChecksumValidation(clientConfig)); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-internal-defaults-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-internal-defaults-class.java index 5ecb09b82593..65c08bc68eaa 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-internal-defaults-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-internal-defaults-class.java @@ -1,10 +1,12 @@ package software.amazon.awssdk.services.json; +import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; @@ -13,28 +15,32 @@ import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.SdkPlugin; 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.exception.SdkClientException; import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; import software.amazon.awssdk.core.retry.RetryMode; +import software.amazon.awssdk.endpoints.Endpoint; import software.amazon.awssdk.http.auth.aws.scheme.AwsV4AuthScheme; import software.amazon.awssdk.http.auth.scheme.NoAuthAuthScheme; import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme; import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; -import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeProvider; import software.amazon.awssdk.services.json.auth.scheme.internal.JsonAuthSchemeInterceptor; +import software.amazon.awssdk.services.json.endpoints.JsonEndpointParams; import software.amazon.awssdk.services.json.endpoints.JsonEndpointProvider; import software.amazon.awssdk.services.json.endpoints.internal.JsonRequestSetEndpointInterceptor; import software.amazon.awssdk.services.json.endpoints.internal.JsonResolveEndpointInterceptor; import software.amazon.awssdk.services.json.internal.JsonServiceClientConfigurationBuilder; import software.amazon.awssdk.utils.CollectionUtils; +import software.amazon.awssdk.utils.CompletableFutureUtils; /** * Internal base class for {@link DefaultJsonClientBuilder} and {@link DefaultJsonAsyncClientBuilder}. @@ -98,20 +104,33 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") - .serviceProfileProperty("json_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + c -> { + Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson").serviceProfileProperty("json_service") + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); + if (endpointFromOverrides.isPresent()) { + return endpointFromOverrides.get(); + } + URI clientEndpointUri = null; + try { + JsonEndpointParams endpointParams = JsonEndpointParams.builder() + .region(c.get(AwsClientOption.AWS_REGION)).build(); + Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( + endpointParams)); + clientEndpointUri = endpoint.url(); + } catch (Exception e) { + // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + return ClientEndpointProvider.create(URI.create("https://localhost"), false); + } + if (clientEndpointUri.getHost() == null) { + throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) + + ") resulted in an invalid URI: " + clientEndpointUri + + ". This is usually caused by an invalid region configuration."); + } + return ClientEndpointProvider.create(clientEndpointUri, false); + }); builder.option(SdkClientJsonProtocolAdvancedOption.ENABLE_FAST_UNMARSHALLER, true); return builder.build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java index 117e19038881..0699b45ee18d 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java @@ -1,10 +1,12 @@ package software.amazon.awssdk.services.json; +import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; @@ -15,6 +17,7 @@ import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.checksums.RequestChecksumCalculation; import software.amazon.awssdk.core.checksums.RequestChecksumCalculationResolver; @@ -23,9 +26,11 @@ 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.exception.SdkClientException; import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; import software.amazon.awssdk.core.retry.RetryMode; +import software.amazon.awssdk.endpoints.Endpoint; import software.amazon.awssdk.http.auth.aws.scheme.AwsV4AuthScheme; import software.amazon.awssdk.http.auth.scheme.BearerAuthScheme; import software.amazon.awssdk.http.auth.scheme.NoAuthAuthScheme; @@ -34,16 +39,17 @@ import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; -import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeProvider; import software.amazon.awssdk.services.json.auth.scheme.internal.JsonAuthSchemeInterceptor; import software.amazon.awssdk.services.json.endpoints.JsonClientContextParams; +import software.amazon.awssdk.services.json.endpoints.JsonEndpointParams; import software.amazon.awssdk.services.json.endpoints.JsonEndpointProvider; import software.amazon.awssdk.services.json.endpoints.internal.JsonRequestSetEndpointInterceptor; import software.amazon.awssdk.services.json.endpoints.internal.JsonResolveEndpointInterceptor; import software.amazon.awssdk.services.json.internal.JsonServiceClientConfigurationBuilder; import software.amazon.awssdk.utils.CollectionUtils; +import software.amazon.awssdk.utils.CompletableFutureUtils; import software.amazon.awssdk.utils.Validate; /** @@ -115,20 +121,33 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(SdkClientOption.SERVICE_CONFIGURATION, finalServiceConfig); builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") - .serviceProfileProperty("json_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + c -> { + Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson").serviceProfileProperty("json_service") + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); + if (endpointFromOverrides.isPresent()) { + return endpointFromOverrides.get(); + } + URI clientEndpointUri = null; + try { + JsonEndpointParams endpointParams = JsonEndpointParams.builder() + .region(c.get(AwsClientOption.AWS_REGION)).build(); + Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( + endpointParams)); + clientEndpointUri = endpoint.url(); + } catch (Exception e) { + // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + return ClientEndpointProvider.create(URI.create("https://localhost"), false); + } + if (clientEndpointUri.getHost() == null) { + throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) + + ") resulted in an invalid URI: " + clientEndpointUri + + ". This is usually caused by an invalid region configuration."); + } + return ClientEndpointProvider.create(clientEndpointUri, false); + }); builder.option(SdkClientJsonProtocolAdvancedOption.ENABLE_FAST_UNMARSHALLER, true); SdkClientConfiguration clientConfig = config; builder.lazyOption(SdkClientOption.REQUEST_CHECKSUM_CALCULATION, c -> resolveRequestChecksumCalculation(clientConfig)); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-env-bearer-token-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-env-bearer-token-client-builder-class.java index 48ecf08535fa..e9fe8afa7ee7 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-env-bearer-token-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-env-bearer-token-client-builder-class.java @@ -1,5 +1,6 @@ package software.amazon.awssdk.services.json; +import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -17,15 +18,18 @@ import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.SdkPlugin; 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.exception.SdkClientException; import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory; import software.amazon.awssdk.core.interceptor.ExecutionAttributes; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute; import software.amazon.awssdk.core.retry.RetryMode; +import software.amazon.awssdk.endpoints.Endpoint; import software.amazon.awssdk.http.auth.scheme.BearerAuthScheme; import software.amazon.awssdk.http.auth.scheme.NoAuthAuthScheme; import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme; @@ -33,16 +37,17 @@ import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; -import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeProvider; import software.amazon.awssdk.services.json.auth.scheme.internal.JsonAuthSchemeInterceptor; +import software.amazon.awssdk.services.json.endpoints.JsonEndpointParams; import software.amazon.awssdk.services.json.endpoints.JsonEndpointProvider; import software.amazon.awssdk.services.json.endpoints.internal.JsonRequestSetEndpointInterceptor; import software.amazon.awssdk.services.json.endpoints.internal.JsonResolveEndpointInterceptor; import software.amazon.awssdk.services.json.internal.EnvironmentTokenSystemSettings; import software.amazon.awssdk.services.json.internal.JsonServiceClientConfigurationBuilder; import software.amazon.awssdk.utils.CollectionUtils; +import software.amazon.awssdk.utils.CompletableFutureUtils; import software.amazon.awssdk.utils.Validate; /** @@ -113,20 +118,33 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson") - .serviceProfileProperty("json_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + c -> { + Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson").serviceProfileProperty("json_service") + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); + if (endpointFromOverrides.isPresent()) { + return endpointFromOverrides.get(); + } + URI clientEndpointUri = null; + try { + JsonEndpointParams endpointParams = JsonEndpointParams.builder() + .region(c.get(AwsClientOption.AWS_REGION)).build(); + Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( + endpointParams)); + clientEndpointUri = endpoint.url(); + } catch (Exception e) { + // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + return ClientEndpointProvider.create(URI.create("https://localhost"), false); + } + if (clientEndpointUri.getHost() == null) { + throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) + + ") resulted in an invalid URI: " + clientEndpointUri + + ". This is usually caused by an invalid region configuration."); + } + return ClientEndpointProvider.create(clientEndpointUri, false); + }); builder.option(SdkClientJsonProtocolAdvancedOption.ENABLE_FAST_UNMARSHALLER, true); return builder.build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-service-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-service-client-builder-class.java index 76c1cd2fc7eb..afad3a3450c2 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-service-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-service-client-builder-class.java @@ -1,10 +1,12 @@ package software.amazon.awssdk.services.h2; +import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; @@ -13,13 +15,16 @@ import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.SdkPlugin; 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.exception.SdkClientException; import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; import software.amazon.awssdk.core.retry.RetryMode; +import software.amazon.awssdk.endpoints.Endpoint; import software.amazon.awssdk.http.Protocol; import software.amazon.awssdk.http.ProtocolNegotiation; import software.amazon.awssdk.http.SdkHttpConfigurationOption; @@ -29,16 +34,17 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; -import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.h2.auth.scheme.H2AuthSchemeProvider; import software.amazon.awssdk.services.h2.auth.scheme.internal.H2AuthSchemeInterceptor; +import software.amazon.awssdk.services.h2.endpoints.H2EndpointParams; import software.amazon.awssdk.services.h2.endpoints.H2EndpointProvider; import software.amazon.awssdk.services.h2.endpoints.internal.H2RequestSetEndpointInterceptor; import software.amazon.awssdk.services.h2.endpoints.internal.H2ResolveEndpointInterceptor; import software.amazon.awssdk.services.h2.internal.H2ServiceClientConfigurationBuilder; import software.amazon.awssdk.utils.AttributeMap; import software.amazon.awssdk.utils.CollectionUtils; +import software.amazon.awssdk.utils.CompletableFutureUtils; /** * Internal base class for {@link DefaultH2ClientBuilder} and {@link DefaultH2AsyncClientBuilder}. @@ -93,20 +99,33 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_H2_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlH2") - .serviceProfileProperty("h2_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + c -> { + Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_H2_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlH2").serviceProfileProperty("h2_service") + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); + if (endpointFromOverrides.isPresent()) { + return endpointFromOverrides.get(); + } + URI clientEndpointUri = null; + try { + H2EndpointParams endpointParams = H2EndpointParams.builder().region(c.get(AwsClientOption.AWS_REGION)) + .build(); + Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( + endpointParams)); + clientEndpointUri = endpoint.url(); + } catch (Exception e) { + // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + return ClientEndpointProvider.create(URI.create("https://localhost"), false); + } + if (clientEndpointUri.getHost() == null) { + throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) + + ") resulted in an invalid URI: " + clientEndpointUri + + ". This is usually caused by an invalid region configuration."); + } + return ClientEndpointProvider.create(clientEndpointUri, false); + }); builder.option(SdkClientJsonProtocolAdvancedOption.ENABLE_FAST_UNMARSHALLER, true); return builder.build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-usePriorKnowledgeForH2-service-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-usePriorKnowledgeForH2-service-client-builder-class.java index d3fc4996de98..0431cb0c92a3 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-usePriorKnowledgeForH2-service-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-usePriorKnowledgeForH2-service-client-builder-class.java @@ -1,10 +1,12 @@ package software.amazon.awssdk.services.h2; +import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; @@ -13,13 +15,16 @@ import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.SdkPlugin; 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.exception.SdkClientException; import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; import software.amazon.awssdk.core.retry.RetryMode; +import software.amazon.awssdk.endpoints.Endpoint; import software.amazon.awssdk.http.Protocol; import software.amazon.awssdk.http.SdkHttpConfigurationOption; import software.amazon.awssdk.http.auth.aws.scheme.AwsV4AuthScheme; @@ -28,16 +33,17 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; -import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.h2.auth.scheme.H2AuthSchemeProvider; import software.amazon.awssdk.services.h2.auth.scheme.internal.H2AuthSchemeInterceptor; +import software.amazon.awssdk.services.h2.endpoints.H2EndpointParams; import software.amazon.awssdk.services.h2.endpoints.H2EndpointProvider; import software.amazon.awssdk.services.h2.endpoints.internal.H2RequestSetEndpointInterceptor; import software.amazon.awssdk.services.h2.endpoints.internal.H2ResolveEndpointInterceptor; import software.amazon.awssdk.services.h2.internal.H2ServiceClientConfigurationBuilder; import software.amazon.awssdk.utils.AttributeMap; import software.amazon.awssdk.utils.CollectionUtils; +import software.amazon.awssdk.utils.CompletableFutureUtils; /** * Internal base class for {@link DefaultH2ClientBuilder} and {@link DefaultH2AsyncClientBuilder}. @@ -92,20 +98,33 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_H2_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlH2") - .serviceProfileProperty("h2_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + c -> { + Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_H2_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlH2").serviceProfileProperty("h2_service") + .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); + if (endpointFromOverrides.isPresent()) { + return endpointFromOverrides.get(); + } + URI clientEndpointUri = null; + try { + H2EndpointParams endpointParams = H2EndpointParams.builder().region(c.get(AwsClientOption.AWS_REGION)) + .build(); + Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( + endpointParams)); + clientEndpointUri = endpoint.url(); + } catch (Exception e) { + // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + return ClientEndpointProvider.create(URI.create("https://localhost"), false); + } + if (clientEndpointUri.getHost() == null) { + throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) + + ") resulted in an invalid URI: " + clientEndpointUri + + ". This is usually caused by an invalid region configuration."); + } + return ClientEndpointProvider.create(clientEndpointUri, false); + }); builder.option(SdkClientJsonProtocolAdvancedOption.ENABLE_FAST_UNMARSHALLER, true); return builder.build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-multi-auth-sigv4a-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-multi-auth-sigv4a-client-builder-class.java index 75faf2cad7a8..50ec3572d59d 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-multi-auth-sigv4a-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-multi-auth-sigv4a-client-builder-class.java @@ -1,10 +1,12 @@ package software.amazon.awssdk.services.database; +import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; @@ -13,13 +15,16 @@ import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.SdkPlugin; 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.exception.SdkClientException; import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; import software.amazon.awssdk.core.retry.RetryMode; +import software.amazon.awssdk.endpoints.Endpoint; import software.amazon.awssdk.http.auth.aws.scheme.AwsV4AuthScheme; import software.amazon.awssdk.http.auth.aws.scheme.AwsV4aAuthScheme; import software.amazon.awssdk.http.auth.aws.signer.RegionSet; @@ -28,15 +33,16 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; -import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.database.auth.scheme.DatabaseAuthSchemeProvider; import software.amazon.awssdk.services.database.auth.scheme.internal.DatabaseAuthSchemeInterceptor; +import software.amazon.awssdk.services.database.endpoints.DatabaseEndpointParams; import software.amazon.awssdk.services.database.endpoints.DatabaseEndpointProvider; import software.amazon.awssdk.services.database.endpoints.internal.DatabaseRequestSetEndpointInterceptor; import software.amazon.awssdk.services.database.endpoints.internal.DatabaseResolveEndpointInterceptor; import software.amazon.awssdk.services.database.internal.DatabaseServiceClientConfigurationBuilder; import software.amazon.awssdk.utils.CollectionUtils; +import software.amazon.awssdk.utils.CompletableFutureUtils; /** * Internal base class for {@link DefaultDatabaseClientBuilder} and {@link DefaultDatabaseAsyncClientBuilder}. @@ -92,20 +98,33 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") - .serviceProfileProperty("database_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + c -> { + Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") + .serviceProfileProperty("database_service").profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); + if (endpointFromOverrides.isPresent()) { + return endpointFromOverrides.get(); + } + URI clientEndpointUri = null; + try { + DatabaseEndpointParams endpointParams = DatabaseEndpointParams.builder() + .region(c.get(AwsClientOption.AWS_REGION)).build(); + Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( + endpointParams)); + clientEndpointUri = endpoint.url(); + } catch (Exception e) { + // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + return ClientEndpointProvider.create(URI.create("https://localhost"), false); + } + if (clientEndpointUri.getHost() == null) { + throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) + + ") resulted in an invalid URI: " + clientEndpointUri + + ". This is usually caused by an invalid region configuration."); + } + return ClientEndpointProvider.create(clientEndpointUri, false); + }); builder.option(SdkClientJsonProtocolAdvancedOption.ENABLE_FAST_UNMARSHALLER, true); return builder.build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java index 72d4f526bfb3..fd00412b0d81 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java @@ -1,10 +1,12 @@ package software.amazon.awssdk.services.database; +import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; @@ -15,13 +17,16 @@ import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.SdkPlugin; 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.exception.SdkClientException; import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; import software.amazon.awssdk.core.retry.RetryMode; +import software.amazon.awssdk.endpoints.Endpoint; import software.amazon.awssdk.http.auth.aws.scheme.AwsV4AuthScheme; import software.amazon.awssdk.http.auth.scheme.BearerAuthScheme; import software.amazon.awssdk.http.auth.scheme.NoAuthAuthScheme; @@ -30,15 +35,16 @@ import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; -import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.database.auth.scheme.DatabaseAuthSchemeProvider; import software.amazon.awssdk.services.database.auth.scheme.internal.DatabaseAuthSchemeInterceptor; +import software.amazon.awssdk.services.database.endpoints.DatabaseEndpointParams; import software.amazon.awssdk.services.database.endpoints.DatabaseEndpointProvider; import software.amazon.awssdk.services.database.endpoints.internal.DatabaseRequestSetEndpointInterceptor; import software.amazon.awssdk.services.database.endpoints.internal.DatabaseResolveEndpointInterceptor; import software.amazon.awssdk.services.database.internal.DatabaseServiceClientConfigurationBuilder; import software.amazon.awssdk.utils.CollectionUtils; +import software.amazon.awssdk.utils.CompletableFutureUtils; import software.amazon.awssdk.utils.Validate; /** @@ -102,20 +108,33 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") - .serviceProfileProperty("database_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + c -> { + Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") + .serviceProfileProperty("database_service").profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); + if (endpointFromOverrides.isPresent()) { + return endpointFromOverrides.get(); + } + URI clientEndpointUri = null; + try { + DatabaseEndpointParams endpointParams = DatabaseEndpointParams.builder() + .region(c.get(AwsClientOption.AWS_REGION)).build(); + Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( + endpointParams)); + clientEndpointUri = endpoint.url(); + } catch (Exception e) { + // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + return ClientEndpointProvider.create(URI.create("https://localhost"), false); + } + if (clientEndpointUri.getHost() == null) { + throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) + + ") resulted in an invalid URI: " + clientEndpointUri + + ". This is usually caused by an invalid region configuration."); + } + return ClientEndpointProvider.create(clientEndpointUri, false); + }); builder.option(SdkClientJsonProtocolAdvancedOption.ENABLE_FAST_UNMARSHALLER, true); return builder.build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-service-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-service-client-builder-class.java index 0be9c031d828..88ce081576aa 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-service-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-service-client-builder-class.java @@ -1,10 +1,12 @@ package software.amazon.awssdk.services.database; +import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; @@ -13,26 +15,30 @@ import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.SdkPlugin; 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.exception.SdkClientException; import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; import software.amazon.awssdk.core.retry.RetryMode; +import software.amazon.awssdk.endpoints.Endpoint; import software.amazon.awssdk.http.auth.scheme.NoAuthAuthScheme; import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; -import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.database.auth.scheme.DatabaseAuthSchemeProvider; import software.amazon.awssdk.services.database.auth.scheme.internal.DatabaseAuthSchemeInterceptor; +import software.amazon.awssdk.services.database.endpoints.DatabaseEndpointParams; import software.amazon.awssdk.services.database.endpoints.DatabaseEndpointProvider; import software.amazon.awssdk.services.database.endpoints.internal.DatabaseRequestSetEndpointInterceptor; import software.amazon.awssdk.services.database.endpoints.internal.DatabaseResolveEndpointInterceptor; import software.amazon.awssdk.services.database.internal.DatabaseServiceClientConfigurationBuilder; import software.amazon.awssdk.utils.CollectionUtils; +import software.amazon.awssdk.utils.CompletableFutureUtils; /** * Internal base class for {@link DefaultDatabaseClientBuilder} and {@link DefaultDatabaseAsyncClientBuilder}. @@ -84,20 +90,33 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptors); builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") - .serviceProfileProperty("database_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + c -> { + Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") + .serviceProfileProperty("database_service").profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); + if (endpointFromOverrides.isPresent()) { + return endpointFromOverrides.get(); + } + URI clientEndpointUri = null; + try { + DatabaseEndpointParams endpointParams = DatabaseEndpointParams.builder() + .region(c.get(AwsClientOption.AWS_REGION)).build(); + Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( + endpointParams)); + clientEndpointUri = endpoint.url(); + } catch (Exception e) { + // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + return ClientEndpointProvider.create(URI.create("https://localhost"), false); + } + if (clientEndpointUri.getHost() == null) { + throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) + + ") resulted in an invalid URI: " + clientEndpointUri + + ". This is usually caused by an invalid region configuration."); + } + return ClientEndpointProvider.create(clientEndpointUri, false); + }); builder.option(SdkClientJsonProtocolAdvancedOption.ENABLE_FAST_UNMARSHALLER, true); return builder.build(); } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-query-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-query-client-builder-class.java index 19b8d5abbae1..1fe0c3563ff5 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-query-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-query-client-builder-class.java @@ -1,10 +1,12 @@ package software.amazon.awssdk.services.query; +import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; import software.amazon.awssdk.annotations.SdkInternalApi; @@ -17,6 +19,7 @@ import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointMode; import software.amazon.awssdk.awscore.endpoints.AccountIdEndpointModeResolver; import software.amazon.awssdk.awscore.retry.AwsRetryStrategy; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.SdkPlugin; import software.amazon.awssdk.core.checksums.RequestChecksumCalculation; import software.amazon.awssdk.core.checksums.RequestChecksumCalculationResolver; @@ -25,9 +28,11 @@ 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.exception.SdkClientException; import software.amazon.awssdk.core.interceptor.ClasspathInterceptorChainFactory; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; import software.amazon.awssdk.core.retry.RetryMode; +import software.amazon.awssdk.endpoints.Endpoint; import software.amazon.awssdk.http.auth.aws.scheme.AwsV4AuthScheme; import software.amazon.awssdk.http.auth.scheme.BearerAuthScheme; import software.amazon.awssdk.http.auth.scheme.NoAuthAuthScheme; @@ -35,16 +40,17 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; -import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.query.auth.scheme.QueryAuthSchemeProvider; import software.amazon.awssdk.services.query.auth.scheme.internal.QueryAuthSchemeInterceptor; import software.amazon.awssdk.services.query.endpoints.QueryClientContextParams; +import software.amazon.awssdk.services.query.endpoints.QueryEndpointParams; import software.amazon.awssdk.services.query.endpoints.QueryEndpointProvider; import software.amazon.awssdk.services.query.endpoints.internal.QueryRequestSetEndpointInterceptor; import software.amazon.awssdk.services.query.endpoints.internal.QueryResolveEndpointInterceptor; import software.amazon.awssdk.services.query.internal.QueryServiceClientConfigurationBuilder; import software.amazon.awssdk.utils.CollectionUtils; +import software.amazon.awssdk.utils.CompletableFutureUtils; import software.amazon.awssdk.utils.Validate; /** @@ -109,20 +115,35 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.option(AwsClientOption.ACCOUNT_ID_ENDPOINT_MODE, resolveAccountIdEndpointMode(config)); builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, - c -> AwsClientEndpointProvider - .builder() - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_QUERY_SERVICE") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlQuery") - .serviceProfileProperty("query_service") - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol("https") - .region(c.get(AwsClientOption.AWS_REGION)) - .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT, - c.get(ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT)) - .dualstackEnabled(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build()); + c -> { + Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_QUERY_SERVICE") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlQuery") + .serviceProfileProperty("query_service").profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) + .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); + if (endpointFromOverrides.isPresent()) { + return endpointFromOverrides.get(); + } + URI clientEndpointUri = null; + try { + QueryEndpointParams endpointParams = QueryEndpointParams.builder() + .region(c.get(AwsClientOption.AWS_REGION)) + .useDualStack(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) + .useFips(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build(); + Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( + endpointParams)); + clientEndpointUri = endpoint.url(); + } catch (Exception e) { + // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + return ClientEndpointProvider.create(URI.create("https://localhost"), false); + } + if (clientEndpointUri.getHost() == null) { + throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) + + ") resulted in an invalid URI: " + clientEndpointUri + + ". This is usually caused by an invalid region configuration."); + } + return ClientEndpointProvider.create(clientEndpointUri, false); + }); SdkClientConfiguration clientConfig = config; builder.lazyOption(SdkClientOption.REQUEST_CHECKSUM_CALCULATION, c -> resolveRequestChecksumCalculation(clientConfig)); builder.lazyOption(SdkClientOption.RESPONSE_CHECKSUM_VALIDATION, c -> resolveResponseChecksumValidation(clientConfig)); diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java index 0bb5119b369e..62477e95c919 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java @@ -482,5 +482,22 @@ public Builder putAdvancedOption(ServiceMetadataAdvancedOption option, T public AwsClientEndpointProvider build() { return new AwsClientEndpointProvider(this); } + + /** + * Build a {@link ClientEndpointProvider} if an endpoint override or environment-based endpoint is configured. + * Returns {@link Optional#empty()} if no override is found, allowing callers to provide their own fallback. + */ + public Optional buildIfOverridePresent() { + this.serviceEndpointPrefix = null; + this.region = null; + this.protocol = null; + AwsClientEndpointProvider provider = new AwsClientEndpointProvider(this); + try { + provider.clientEndpoint(); + return Optional.of(provider); + } catch (SdkClientException e) { + return Optional.empty(); + } + } } } From c153507ade0acb3f5345365005cfe1f0b5e2c808 Mon Sep 17 00:00:00 2001 From: Saranya Somepalli Date: Wed, 1 Jul 2026 14:01:15 -0700 Subject: [PATCH 2/4] Adding tests --- .../endpoint/AwsClientEndpointProvider.java | 23 +++-- ...intProviderBuildIfOverridePresentTest.java | 94 +++++++++++++++++++ 2 files changed, 109 insertions(+), 8 deletions(-) create mode 100644 core/aws-core/src/test/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProviderBuildIfOverridePresentTest.java diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java index 62477e95c919..609328e1c648 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java @@ -74,6 +74,10 @@ private AwsClientEndpointProvider(Builder builder) { this.clientEndpoint = new Lazy<>(() -> resolveClientEndpoint(new Builder(builder))); } + private AwsClientEndpointProvider(Builder builder, boolean overridesOnly) { + this.clientEndpoint = new Lazy<>(() -> resolveFromOverridesAndEnvironment(new Builder(builder))); + } + public static Builder builder() { return new Builder(); } @@ -95,6 +99,7 @@ public boolean isEndpointOverridden() { return clientEndpoint.getValue().isEndpointOverridden; } + // TODO: Remove once all callers are migrated to use resolveFromOverridesAndEnvironment private ClientEndpoint resolveClientEndpoint(Builder builder) { return OptionalUtils.firstPresent(clientEndpointFromClientOverride(builder), () -> clientEndpointFromEnvironment(builder), @@ -102,6 +107,13 @@ private ClientEndpoint resolveClientEndpoint(Builder builder) { .orElseThrow(AwsClientEndpointProvider::failToLoadEndpointException); } + private ClientEndpoint resolveFromOverridesAndEnvironment(Builder builder) { + initializeProfileFileDefaults(builder); + return OptionalUtils.firstPresent(clientEndpointFromClientOverride(builder), + () -> clientEndpointFromEnvironment(builder)) + .orElse(null); + } + private static SdkClientException failToLoadEndpointException() { return SdkClientException.create("Unable to determine the default client endpoint. Enable TRACE logging on " + AwsClientEndpointProvider.class.getName() + " for more information."); @@ -488,16 +500,11 @@ public AwsClientEndpointProvider build() { * Returns {@link Optional#empty()} if no override is found, allowing callers to provide their own fallback. */ public Optional buildIfOverridePresent() { - this.serviceEndpointPrefix = null; - this.region = null; - this.protocol = null; - AwsClientEndpointProvider provider = new AwsClientEndpointProvider(this); - try { - provider.clientEndpoint(); - return Optional.of(provider); - } catch (SdkClientException e) { + AwsClientEndpointProvider provider = new AwsClientEndpointProvider(this, true); + if (provider.clientEndpoint.getValue() == null) { return Optional.empty(); } + return Optional.of(provider); } } } diff --git a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProviderBuildIfOverridePresentTest.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProviderBuildIfOverridePresentTest.java new file mode 100644 index 000000000000..0ce987e7b71b --- /dev/null +++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProviderBuildIfOverridePresentTest.java @@ -0,0 +1,94 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.awscore.endpoint; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.net.URI; +import java.util.Optional; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.core.ClientEndpointProvider; + +class AwsClientEndpointProviderBuildIfOverridePresentTest { + + private static final String TEST_SYSTEM_PROPERTY = "aws.endpointUrlTestService"; + + @AfterEach + void cleanup() { + System.clearProperty(TEST_SYSTEM_PROPERTY); + } + + @Test + void buildIfOverridePresent_withClientEndpointOverride_returnsProviderWithOverride() { + URI override = URI.create("https://custom-endpoint.example.com"); + + Optional result = AwsClientEndpointProvider.builder() + .clientEndpointOverride(override) + .buildIfOverridePresent(); + + assertThat(result).isPresent(); + assertThat(result.get().clientEndpoint()).isEqualTo(override); + assertThat(result.get().isEndpointOverridden()).isTrue(); + } + + @Test + void buildIfOverridePresent_withSystemPropertyEndpoint_returnsProviderWithEndpoint() { + System.setProperty(TEST_SYSTEM_PROPERTY, "https://sys-prop-endpoint.example.com"); + + Optional result = AwsClientEndpointProvider.builder() + .serviceEndpointOverrideSystemProperty(TEST_SYSTEM_PROPERTY) + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_TEST_SERVICE") + .serviceProfileProperty("testservice") + .buildIfOverridePresent(); + + assertThat(result).isPresent(); + assertThat(result.get().clientEndpoint()) + .isEqualTo(URI.create("https://sys-prop-endpoint.example.com")); + assertThat(result.get().isEndpointOverridden()).isTrue(); + } + + @Test + void buildIfOverridePresent_withNoOverrideOrEnvironment_returnsEmpty() { + Optional result = AwsClientEndpointProvider.builder() + .serviceEndpointOverrideSystemProperty("aws.endpointUrlNonExistent") + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_NON_EXISTENT") + .serviceProfileProperty("nonexistent") + .buildIfOverridePresent(); + + assertThat(result).isEmpty(); + } + + @Test + void buildIfOverridePresent_withNoParamsConfigured_returnsEmpty() { + Optional result = AwsClientEndpointProvider.builder() + .buildIfOverridePresent(); + + assertThat(result).isEmpty(); + } + + @Test + void buildIfOverridePresent_withoutServiceMetadataParams_returnsProviderWithOverride() { + URI override = URI.create("https://override.example.com"); + + Optional result = AwsClientEndpointProvider.builder() + .clientEndpointOverride(override) + .buildIfOverridePresent(); + + assertThat(result).isPresent(); + assertThat(result.get().clientEndpoint()).isEqualTo(override); + } +} From f85951b4c28587708c9f4f9e1fbab891799dab2e Mon Sep 17 00:00:00 2001 From: Saranya Somepalli Date: Wed, 1 Jul 2026 15:07:22 -0700 Subject: [PATCH 3/4] Additional changes --- .../poet/builder/BaseClientBuilderClass.java | 16 ++++++++++------ .../test-bearer-auth-client-builder-class.java | 15 ++++++++------- .../poet/builder/test-client-builder-class.java | 15 ++++++++------- ...est-client-builder-endpoints-auth-params.java | 15 ++++++++------- ...t-client-builder-internal-defaults-class.java | 15 ++++++++------- ...est-composed-sync-default-client-builder.java | 15 ++++++++------- ...st-env-bearer-token-client-builder-class.java | 15 ++++++++------- .../test-h2-service-client-builder-class.java | 15 ++++++++------- ...wledgeForH2-service-client-builder-class.java | 15 ++++++++------- ...t-multi-auth-sigv4a-client-builder-class.java | 15 ++++++++------- .../test-no-auth-ops-client-builder-class.java | 15 ++++++++------- ...est-no-auth-service-client-builder-class.java | 15 ++++++++------- .../builder/test-query-client-builder-class.java | 15 ++++++++------- 13 files changed, 106 insertions(+), 90 deletions(-) diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java index 5772aa2540a2..3c4dc8334866 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java @@ -529,10 +529,13 @@ private MethodSpec finalizeServiceConfigurationMethod() { .addCode(" return endpointFromOverrides.get();\n") .addCode(" }\n") .addCode(" $T clientEndpointUri = null;\n", URI.class) + .addCode(" $T region = c.get($T.AWS_REGION);\n", + ClassName.get("software.amazon.awssdk.regions", "Region"), + AwsClientOption.class) .addCode(" try {\n") .addCode(" $T endpointParams = $T.builder()\n", endpointRulesSpecUtils.parametersClassName(), endpointRulesSpecUtils.parametersClassName()) - .addCode(" .region(c.get($T.AWS_REGION))\n", AwsClientOption.class); + .addCode(" .region(region)\n"); if (hasBuiltIn(BuiltInParameter.AWS_USE_DUAL_STACK)) { builder.addCode(" .useDualStack(c.get($T.DUALSTACK_ENDPOINT_ENABLED))\n", AwsClientOption.class); @@ -546,16 +549,17 @@ private MethodSpec finalizeServiceConfigurationMethod() { ClassName.get("software.amazon.awssdk.endpoints", "Endpoint"), ClassName.get("software.amazon.awssdk.utils", "CompletableFutureUtils")) .addCode(" clientEndpointUri = endpoint.url();\n") - .addCode(" } catch (Exception e) {\n") - .addCode(" // Resolution requires request-bound params; fallback to placeholder, resolved at request time.\n") + .addCode(" } catch ($T e) {\n", + ClassName.get("software.amazon.awssdk.core.exception", "SdkClientException")) + .addCode(" // Endpoint resolution failed. This is expected for services that require request-bound\n") + .addCode(" // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time.\n") .addCode(" return $T.create($T.create($S), false);\n", ClassName.get("software.amazon.awssdk.core", "ClientEndpointProvider"), URI.class, "https://localhost") .addCode(" }\n") .addCode(" if (clientEndpointUri.getHost() == null) {\n") - .addCode(" throw $T.create(\"Configured region (\" + c.get($T.AWS_REGION)\n", - ClassName.get("software.amazon.awssdk.core.exception", "SdkClientException"), - AwsClientOption.class) + .addCode(" throw $T.create(\"Configured region (\" + region\n", + ClassName.get("software.amazon.awssdk.core.exception", "SdkClientException")) .addCode(" + \") resulted in an invalid URI: \" + clientEndpointUri\n") .addCode(" + \". This is usually caused by an invalid region configuration.\");\n") .addCode(" }\n") diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-bearer-auth-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-bearer-auth-client-builder-class.java index 57e70c6b7864..3203e4db5b30 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-bearer-auth-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-bearer-auth-client-builder-class.java @@ -34,6 +34,7 @@ import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; +import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeProvider; import software.amazon.awssdk.services.json.auth.scheme.internal.JsonAuthSchemeInterceptor; @@ -112,20 +113,20 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon return endpointFromOverrides.get(); } URI clientEndpointUri = null; + Region region = c.get(AwsClientOption.AWS_REGION); try { - JsonEndpointParams endpointParams = JsonEndpointParams.builder() - .region(c.get(AwsClientOption.AWS_REGION)).build(); + JsonEndpointParams endpointParams = JsonEndpointParams.builder().region(region).build(); Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (Exception e) { - // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + } catch (SdkClientException e) { + // Endpoint resolution failed. This is expected for services that require request-bound + // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { - throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) - + ") resulted in an invalid URI: " + clientEndpointUri - + ". This is usually caused by an invalid region configuration."); + throw SdkClientException.create("Configured region (" + region + ") resulted in an invalid URI: " + + clientEndpointUri + ". This is usually caused by an invalid region configuration."); } return ClientEndpointProvider.create(clientEndpointUri, false); }); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-class.java index 89afff11fc92..24df86feea30 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-class.java @@ -43,6 +43,7 @@ import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; +import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeProvider; import software.amazon.awssdk.services.json.auth.scheme.internal.JsonAuthSchemeInterceptor; @@ -208,20 +209,20 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon return endpointFromOverrides.get(); } URI clientEndpointUri = null; + Region region = c.get(AwsClientOption.AWS_REGION); try { - JsonEndpointParams endpointParams = JsonEndpointParams.builder() - .region(c.get(AwsClientOption.AWS_REGION)).build(); + JsonEndpointParams endpointParams = JsonEndpointParams.builder().region(region).build(); Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (Exception e) { - // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + } catch (SdkClientException e) { + // Endpoint resolution failed. This is expected for services that require request-bound + // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { - throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) - + ") resulted in an invalid URI: " + clientEndpointUri - + ". This is usually caused by an invalid region configuration."); + throw SdkClientException.create("Configured region (" + region + ") resulted in an invalid URI: " + + clientEndpointUri + ". This is usually caused by an invalid region configuration."); } return ClientEndpointProvider.create(clientEndpointUri, false); }); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-endpoints-auth-params.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-endpoints-auth-params.java index 9d3b7b0d5e8b..65086d5986c9 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-endpoints-auth-params.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-endpoints-auth-params.java @@ -42,6 +42,7 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; +import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.query.auth.scheme.QueryAuthSchemeProvider; import software.amazon.awssdk.services.query.auth.scheme.internal.QueryAuthSchemeInterceptor; @@ -127,22 +128,22 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon return endpointFromOverrides.get(); } URI clientEndpointUri = null; + Region region = c.get(AwsClientOption.AWS_REGION); try { - QueryEndpointParams endpointParams = QueryEndpointParams.builder() - .region(c.get(AwsClientOption.AWS_REGION)) + QueryEndpointParams endpointParams = QueryEndpointParams.builder().region(region) .useDualStack(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) .useFips(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build(); Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (Exception e) { - // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + } catch (SdkClientException e) { + // Endpoint resolution failed. This is expected for services that require request-bound + // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { - throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) - + ") resulted in an invalid URI: " + clientEndpointUri - + ". This is usually caused by an invalid region configuration."); + throw SdkClientException.create("Configured region (" + region + ") resulted in an invalid URI: " + + clientEndpointUri + ". This is usually caused by an invalid region configuration."); } return ClientEndpointProvider.create(clientEndpointUri, false); }); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-internal-defaults-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-internal-defaults-class.java index 65c08bc68eaa..38b52129b056 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-internal-defaults-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-internal-defaults-class.java @@ -31,6 +31,7 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; +import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeProvider; import software.amazon.awssdk.services.json.auth.scheme.internal.JsonAuthSchemeInterceptor; @@ -114,20 +115,20 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon return endpointFromOverrides.get(); } URI clientEndpointUri = null; + Region region = c.get(AwsClientOption.AWS_REGION); try { - JsonEndpointParams endpointParams = JsonEndpointParams.builder() - .region(c.get(AwsClientOption.AWS_REGION)).build(); + JsonEndpointParams endpointParams = JsonEndpointParams.builder().region(region).build(); Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (Exception e) { - // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + } catch (SdkClientException e) { + // Endpoint resolution failed. This is expected for services that require request-bound + // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { - throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) - + ") resulted in an invalid URI: " + clientEndpointUri - + ". This is usually caused by an invalid region configuration."); + throw SdkClientException.create("Configured region (" + region + ") resulted in an invalid URI: " + + clientEndpointUri + ". This is usually caused by an invalid region configuration."); } return ClientEndpointProvider.create(clientEndpointUri, false); }); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java index 0699b45ee18d..4cb40a0e358c 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java @@ -39,6 +39,7 @@ import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; +import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeProvider; import software.amazon.awssdk.services.json.auth.scheme.internal.JsonAuthSchemeInterceptor; @@ -131,20 +132,20 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon return endpointFromOverrides.get(); } URI clientEndpointUri = null; + Region region = c.get(AwsClientOption.AWS_REGION); try { - JsonEndpointParams endpointParams = JsonEndpointParams.builder() - .region(c.get(AwsClientOption.AWS_REGION)).build(); + JsonEndpointParams endpointParams = JsonEndpointParams.builder().region(region).build(); Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (Exception e) { - // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + } catch (SdkClientException e) { + // Endpoint resolution failed. This is expected for services that require request-bound + // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { - throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) - + ") resulted in an invalid URI: " + clientEndpointUri - + ". This is usually caused by an invalid region configuration."); + throw SdkClientException.create("Configured region (" + region + ") resulted in an invalid URI: " + + clientEndpointUri + ". This is usually caused by an invalid region configuration."); } return ClientEndpointProvider.create(clientEndpointUri, false); }); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-env-bearer-token-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-env-bearer-token-client-builder-class.java index e9fe8afa7ee7..cf2c43a768f6 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-env-bearer-token-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-env-bearer-token-client-builder-class.java @@ -37,6 +37,7 @@ import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; +import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.json.auth.scheme.JsonAuthSchemeProvider; import software.amazon.awssdk.services.json.auth.scheme.internal.JsonAuthSchemeInterceptor; @@ -128,20 +129,20 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon return endpointFromOverrides.get(); } URI clientEndpointUri = null; + Region region = c.get(AwsClientOption.AWS_REGION); try { - JsonEndpointParams endpointParams = JsonEndpointParams.builder() - .region(c.get(AwsClientOption.AWS_REGION)).build(); + JsonEndpointParams endpointParams = JsonEndpointParams.builder().region(region).build(); Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (Exception e) { - // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + } catch (SdkClientException e) { + // Endpoint resolution failed. This is expected for services that require request-bound + // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { - throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) - + ") resulted in an invalid URI: " + clientEndpointUri - + ". This is usually caused by an invalid region configuration."); + throw SdkClientException.create("Configured region (" + region + ") resulted in an invalid URI: " + + clientEndpointUri + ". This is usually caused by an invalid region configuration."); } return ClientEndpointProvider.create(clientEndpointUri, false); }); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-service-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-service-client-builder-class.java index afad3a3450c2..7c100a8b8546 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-service-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-service-client-builder-class.java @@ -34,6 +34,7 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; +import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.h2.auth.scheme.H2AuthSchemeProvider; import software.amazon.awssdk.services.h2.auth.scheme.internal.H2AuthSchemeInterceptor; @@ -109,20 +110,20 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon return endpointFromOverrides.get(); } URI clientEndpointUri = null; + Region region = c.get(AwsClientOption.AWS_REGION); try { - H2EndpointParams endpointParams = H2EndpointParams.builder().region(c.get(AwsClientOption.AWS_REGION)) - .build(); + H2EndpointParams endpointParams = H2EndpointParams.builder().region(region).build(); Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (Exception e) { - // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + } catch (SdkClientException e) { + // Endpoint resolution failed. This is expected for services that require request-bound + // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { - throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) - + ") resulted in an invalid URI: " + clientEndpointUri - + ". This is usually caused by an invalid region configuration."); + throw SdkClientException.create("Configured region (" + region + ") resulted in an invalid URI: " + + clientEndpointUri + ". This is usually caused by an invalid region configuration."); } return ClientEndpointProvider.create(clientEndpointUri, false); }); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-usePriorKnowledgeForH2-service-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-usePriorKnowledgeForH2-service-client-builder-class.java index 0431cb0c92a3..63b4bab902d7 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-usePriorKnowledgeForH2-service-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-usePriorKnowledgeForH2-service-client-builder-class.java @@ -33,6 +33,7 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; +import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.h2.auth.scheme.H2AuthSchemeProvider; import software.amazon.awssdk.services.h2.auth.scheme.internal.H2AuthSchemeInterceptor; @@ -108,20 +109,20 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon return endpointFromOverrides.get(); } URI clientEndpointUri = null; + Region region = c.get(AwsClientOption.AWS_REGION); try { - H2EndpointParams endpointParams = H2EndpointParams.builder().region(c.get(AwsClientOption.AWS_REGION)) - .build(); + H2EndpointParams endpointParams = H2EndpointParams.builder().region(region).build(); Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (Exception e) { - // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + } catch (SdkClientException e) { + // Endpoint resolution failed. This is expected for services that require request-bound + // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { - throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) - + ") resulted in an invalid URI: " + clientEndpointUri - + ". This is usually caused by an invalid region configuration."); + throw SdkClientException.create("Configured region (" + region + ") resulted in an invalid URI: " + + clientEndpointUri + ". This is usually caused by an invalid region configuration."); } return ClientEndpointProvider.create(clientEndpointUri, false); }); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-multi-auth-sigv4a-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-multi-auth-sigv4a-client-builder-class.java index 50ec3572d59d..f28a2af9382d 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-multi-auth-sigv4a-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-multi-auth-sigv4a-client-builder-class.java @@ -33,6 +33,7 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; +import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.database.auth.scheme.DatabaseAuthSchemeProvider; import software.amazon.awssdk.services.database.auth.scheme.internal.DatabaseAuthSchemeInterceptor; @@ -108,20 +109,20 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon return endpointFromOverrides.get(); } URI clientEndpointUri = null; + Region region = c.get(AwsClientOption.AWS_REGION); try { - DatabaseEndpointParams endpointParams = DatabaseEndpointParams.builder() - .region(c.get(AwsClientOption.AWS_REGION)).build(); + DatabaseEndpointParams endpointParams = DatabaseEndpointParams.builder().region(region).build(); Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (Exception e) { - // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + } catch (SdkClientException e) { + // Endpoint resolution failed. This is expected for services that require request-bound + // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { - throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) - + ") resulted in an invalid URI: " + clientEndpointUri - + ". This is usually caused by an invalid region configuration."); + throw SdkClientException.create("Configured region (" + region + ") resulted in an invalid URI: " + + clientEndpointUri + ". This is usually caused by an invalid region configuration."); } return ClientEndpointProvider.create(clientEndpointUri, false); }); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java index fd00412b0d81..f6e6223c9936 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java @@ -35,6 +35,7 @@ import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; +import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.database.auth.scheme.DatabaseAuthSchemeProvider; import software.amazon.awssdk.services.database.auth.scheme.internal.DatabaseAuthSchemeInterceptor; @@ -118,20 +119,20 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon return endpointFromOverrides.get(); } URI clientEndpointUri = null; + Region region = c.get(AwsClientOption.AWS_REGION); try { - DatabaseEndpointParams endpointParams = DatabaseEndpointParams.builder() - .region(c.get(AwsClientOption.AWS_REGION)).build(); + DatabaseEndpointParams endpointParams = DatabaseEndpointParams.builder().region(region).build(); Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (Exception e) { - // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + } catch (SdkClientException e) { + // Endpoint resolution failed. This is expected for services that require request-bound + // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { - throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) - + ") resulted in an invalid URI: " + clientEndpointUri - + ". This is usually caused by an invalid region configuration."); + throw SdkClientException.create("Configured region (" + region + ") resulted in an invalid URI: " + + clientEndpointUri + ". This is usually caused by an invalid region configuration."); } return ClientEndpointProvider.create(clientEndpointUri, false); }); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-service-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-service-client-builder-class.java index 88ce081576aa..a4a01fe92b2d 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-service-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-service-client-builder-class.java @@ -29,6 +29,7 @@ import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; +import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.database.auth.scheme.DatabaseAuthSchemeProvider; import software.amazon.awssdk.services.database.auth.scheme.internal.DatabaseAuthSchemeInterceptor; @@ -100,20 +101,20 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon return endpointFromOverrides.get(); } URI clientEndpointUri = null; + Region region = c.get(AwsClientOption.AWS_REGION); try { - DatabaseEndpointParams endpointParams = DatabaseEndpointParams.builder() - .region(c.get(AwsClientOption.AWS_REGION)).build(); + DatabaseEndpointParams endpointParams = DatabaseEndpointParams.builder().region(region).build(); Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (Exception e) { - // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + } catch (SdkClientException e) { + // Endpoint resolution failed. This is expected for services that require request-bound + // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { - throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) - + ") resulted in an invalid URI: " + clientEndpointUri - + ". This is usually caused by an invalid region configuration."); + throw SdkClientException.create("Configured region (" + region + ") resulted in an invalid URI: " + + clientEndpointUri + ". This is usually caused by an invalid region configuration."); } return ClientEndpointProvider.create(clientEndpointUri, false); }); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-query-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-query-client-builder-class.java index 1fe0c3563ff5..bf5ca575cca5 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-query-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-query-client-builder-class.java @@ -40,6 +40,7 @@ import software.amazon.awssdk.identity.spi.IdentityProvider; import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; +import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.retries.api.RetryStrategy; import software.amazon.awssdk.services.query.auth.scheme.QueryAuthSchemeProvider; import software.amazon.awssdk.services.query.auth.scheme.internal.QueryAuthSchemeInterceptor; @@ -125,22 +126,22 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon return endpointFromOverrides.get(); } URI clientEndpointUri = null; + Region region = c.get(AwsClientOption.AWS_REGION); try { - QueryEndpointParams endpointParams = QueryEndpointParams.builder() - .region(c.get(AwsClientOption.AWS_REGION)) + QueryEndpointParams endpointParams = QueryEndpointParams.builder().region(region) .useDualStack(c.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) .useFips(c.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)).build(); Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (Exception e) { - // Resolution requires request-bound params; fallback to placeholder, resolved at request time. + } catch (SdkClientException e) { + // Endpoint resolution failed. This is expected for services that require request-bound + // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { - throw SdkClientException.create("Configured region (" + c.get(AwsClientOption.AWS_REGION) - + ") resulted in an invalid URI: " + clientEndpointUri - + ". This is usually caused by an invalid region configuration."); + throw SdkClientException.create("Configured region (" + region + ") resulted in an invalid URI: " + + clientEndpointUri + ". This is usually caused by an invalid region configuration."); } return ClientEndpointProvider.create(clientEndpointUri, false); }); From 32fe4e629768ce04b1b9b7539dfbfbdb5ec210dc Mon Sep 17 00:00:00 2001 From: Saranya Somepalli Date: Thu, 2 Jul 2026 13:53:42 -0700 Subject: [PATCH 4/4] Address PR comments --- .../poet/builder/BaseClientBuilderClass.java | 18 +-- ...test-bearer-auth-client-builder-class.java | 14 +-- .../builder/test-client-builder-class.java | 14 +-- ...-client-builder-endpoints-auth-params.java | 14 +-- ...lient-builder-internal-defaults-class.java | 14 +-- ...-composed-sync-default-client-builder.java | 14 +-- ...env-bearer-token-client-builder-class.java | 14 +-- .../test-h2-service-client-builder-class.java | 14 +-- ...dgeForH2-service-client-builder-class.java | 14 +-- ...ulti-auth-sigv4a-client-builder-class.java | 14 +-- ...test-no-auth-ops-client-builder-class.java | 14 +-- ...-no-auth-service-client-builder-class.java | 14 +-- .../test-query-client-builder-class.java | 14 +-- .../endpoint/AwsClientEndpointProvider.java | 51 ++++---- ...ointProviderResolveFromOverridesTest.java} | 45 +++---- .../ClientEndpointResolutionTest.java | 111 ++++++++++++++++++ 16 files changed, 240 insertions(+), 153 deletions(-) rename core/aws-core/src/test/java/software/amazon/awssdk/awscore/endpoint/{AwsClientEndpointProviderBuildIfOverridePresentTest.java => AwsClientEndpointProviderResolveFromOverridesTest.java} (51%) create mode 100644 test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/endpointproviders/ClientEndpointResolutionTest.java diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java index 3c4dc8334866..50a0c5aaa484 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java @@ -516,17 +516,18 @@ private MethodSpec finalizeServiceConfigurationMethod() { String serviceNameForProfileFile = model.getNamingStrategy().getServiceNameForProfileFile(); builder.addCode("builder.lazyOptionIfAbsent($T.CLIENT_ENDPOINT_PROVIDER, c -> {\n", SdkClientOption.class) - .addCode(" $T<$T> endpointFromOverrides = $T.builder()\n", - Optional.class, ClassName.get("software.amazon.awssdk.core", "ClientEndpointProvider"), + .addCode(" $T<$T> overrideEndpoint = $T.builder()\n", + Optional.class, URI.class, AwsClientEndpointProvider.class) .addCode(" .serviceEndpointOverrideEnvironmentVariable($S)\n", "AWS_ENDPOINT_URL_" + serviceNameForEnvVar) .addCode(" .serviceEndpointOverrideSystemProperty($S)\n", "aws.endpointUrl" + serviceNameForSystemProperty) .addCode(" .serviceProfileProperty($S)\n", serviceNameForProfileFile) .addCode(" .profileFile(c.get($T.PROFILE_FILE_SUPPLIER))\n", SdkClientOption.class) .addCode(" .profileName(c.get($T.PROFILE_NAME))\n", SdkClientOption.class) - .addCode(" .buildIfOverridePresent();\n") - .addCode(" if (endpointFromOverrides.isPresent()) {\n") - .addCode(" return endpointFromOverrides.get();\n") + .addCode(" .resolveFromOverrides();\n") + .addCode(" if (overrideEndpoint.isPresent()) {\n") + .addCode(" return $T.create(overrideEndpoint.get(), true);\n", + ClassName.get("software.amazon.awssdk.core", "ClientEndpointProvider")) .addCode(" }\n") .addCode(" $T clientEndpointUri = null;\n", URI.class) .addCode(" $T region = c.get($T.AWS_REGION);\n", @@ -549,10 +550,9 @@ private MethodSpec finalizeServiceConfigurationMethod() { ClassName.get("software.amazon.awssdk.endpoints", "Endpoint"), ClassName.get("software.amazon.awssdk.utils", "CompletableFutureUtils")) .addCode(" clientEndpointUri = endpoint.url();\n") - .addCode(" } catch ($T e) {\n", - ClassName.get("software.amazon.awssdk.core.exception", "SdkClientException")) - .addCode(" // Endpoint resolution failed. This is expected for services that require request-bound\n") - .addCode(" // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time.\n") + .addCode(" } catch (Exception e) {\n") + .addCode(" // Endpoint resolution failed. This is expected for services with required parameters\n") + .addCode(" // beyond region, dualstack, and FIPS. Use a placeholder that will be replaced at request time.\n") .addCode(" return $T.create($T.create($S), false);\n", ClassName.get("software.amazon.awssdk.core", "ClientEndpointProvider"), URI.class, "https://localhost") diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-bearer-auth-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-bearer-auth-client-builder-class.java index 3203e4db5b30..46cda07aba48 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-bearer-auth-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-bearer-auth-client-builder-class.java @@ -104,13 +104,13 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, c -> { - Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + Optional overrideEndpoint = AwsClientEndpointProvider.builder() .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson").serviceProfileProperty("json_service") .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); - if (endpointFromOverrides.isPresent()) { - return endpointFromOverrides.get(); + .profileName(c.get(SdkClientOption.PROFILE_NAME)).resolveFromOverrides(); + if (overrideEndpoint.isPresent()) { + return ClientEndpointProvider.create(overrideEndpoint.get(), true); } URI clientEndpointUri = null; Region region = c.get(AwsClientOption.AWS_REGION); @@ -119,9 +119,9 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (SdkClientException e) { - // Endpoint resolution failed. This is expected for services that require request-bound - // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. + } catch (Exception e) { + // Endpoint resolution failed. This is expected for services with required parameters + // beyond region, dualstack, and FIPS. Use a placeholder that will be replaced at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-class.java index 24df86feea30..325840ed20f6 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-class.java @@ -200,13 +200,13 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, c -> { - Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + Optional overrideEndpoint = AwsClientEndpointProvider.builder() .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson").serviceProfileProperty("json_service") .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); - if (endpointFromOverrides.isPresent()) { - return endpointFromOverrides.get(); + .profileName(c.get(SdkClientOption.PROFILE_NAME)).resolveFromOverrides(); + if (overrideEndpoint.isPresent()) { + return ClientEndpointProvider.create(overrideEndpoint.get(), true); } URI clientEndpointUri = null; Region region = c.get(AwsClientOption.AWS_REGION); @@ -215,9 +215,9 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (SdkClientException e) { - // Endpoint resolution failed. This is expected for services that require request-bound - // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. + } catch (Exception e) { + // Endpoint resolution failed. This is expected for services with required parameters + // beyond region, dualstack, and FIPS. Use a placeholder that will be replaced at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-endpoints-auth-params.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-endpoints-auth-params.java index 65086d5986c9..26db5a5ed38e 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-endpoints-auth-params.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-endpoints-auth-params.java @@ -119,13 +119,13 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, c -> { - Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + Optional overrideEndpoint = AwsClientEndpointProvider.builder() .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_QUERY_SERVICE") .serviceEndpointOverrideSystemProperty("aws.endpointUrlQuery") .serviceProfileProperty("query_service").profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); - if (endpointFromOverrides.isPresent()) { - return endpointFromOverrides.get(); + .profileName(c.get(SdkClientOption.PROFILE_NAME)).resolveFromOverrides(); + if (overrideEndpoint.isPresent()) { + return ClientEndpointProvider.create(overrideEndpoint.get(), true); } URI clientEndpointUri = null; Region region = c.get(AwsClientOption.AWS_REGION); @@ -136,9 +136,9 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (SdkClientException e) { - // Endpoint resolution failed. This is expected for services that require request-bound - // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. + } catch (Exception e) { + // Endpoint resolution failed. This is expected for services with required parameters + // beyond region, dualstack, and FIPS. Use a placeholder that will be replaced at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-internal-defaults-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-internal-defaults-class.java index 38b52129b056..e66864159bbb 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-internal-defaults-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-client-builder-internal-defaults-class.java @@ -106,13 +106,13 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, c -> { - Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + Optional overrideEndpoint = AwsClientEndpointProvider.builder() .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson").serviceProfileProperty("json_service") .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); - if (endpointFromOverrides.isPresent()) { - return endpointFromOverrides.get(); + .profileName(c.get(SdkClientOption.PROFILE_NAME)).resolveFromOverrides(); + if (overrideEndpoint.isPresent()) { + return ClientEndpointProvider.create(overrideEndpoint.get(), true); } URI clientEndpointUri = null; Region region = c.get(AwsClientOption.AWS_REGION); @@ -121,9 +121,9 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (SdkClientException e) { - // Endpoint resolution failed. This is expected for services that require request-bound - // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. + } catch (Exception e) { + // Endpoint resolution failed. This is expected for services with required parameters + // beyond region, dualstack, and FIPS. Use a placeholder that will be replaced at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java index 4cb40a0e358c..3336551a495a 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-composed-sync-default-client-builder.java @@ -123,13 +123,13 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, c -> { - Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + Optional overrideEndpoint = AwsClientEndpointProvider.builder() .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson").serviceProfileProperty("json_service") .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); - if (endpointFromOverrides.isPresent()) { - return endpointFromOverrides.get(); + .profileName(c.get(SdkClientOption.PROFILE_NAME)).resolveFromOverrides(); + if (overrideEndpoint.isPresent()) { + return ClientEndpointProvider.create(overrideEndpoint.get(), true); } URI clientEndpointUri = null; Region region = c.get(AwsClientOption.AWS_REGION); @@ -138,9 +138,9 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (SdkClientException e) { - // Endpoint resolution failed. This is expected for services that require request-bound - // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. + } catch (Exception e) { + // Endpoint resolution failed. This is expected for services with required parameters + // beyond region, dualstack, and FIPS. Use a placeholder that will be replaced at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-env-bearer-token-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-env-bearer-token-client-builder-class.java index cf2c43a768f6..309429696a29 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-env-bearer-token-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-env-bearer-token-client-builder-class.java @@ -120,13 +120,13 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, c -> { - Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + Optional overrideEndpoint = AwsClientEndpointProvider.builder() .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_JSON_SERVICE") .serviceEndpointOverrideSystemProperty("aws.endpointUrlJson").serviceProfileProperty("json_service") .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); - if (endpointFromOverrides.isPresent()) { - return endpointFromOverrides.get(); + .profileName(c.get(SdkClientOption.PROFILE_NAME)).resolveFromOverrides(); + if (overrideEndpoint.isPresent()) { + return ClientEndpointProvider.create(overrideEndpoint.get(), true); } URI clientEndpointUri = null; Region region = c.get(AwsClientOption.AWS_REGION); @@ -135,9 +135,9 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (SdkClientException e) { - // Endpoint resolution failed. This is expected for services that require request-bound - // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. + } catch (Exception e) { + // Endpoint resolution failed. This is expected for services with required parameters + // beyond region, dualstack, and FIPS. Use a placeholder that will be replaced at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-service-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-service-client-builder-class.java index 7c100a8b8546..bf9a78a523a4 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-service-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-service-client-builder-class.java @@ -101,13 +101,13 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, c -> { - Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + Optional overrideEndpoint = AwsClientEndpointProvider.builder() .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_H2_SERVICE") .serviceEndpointOverrideSystemProperty("aws.endpointUrlH2").serviceProfileProperty("h2_service") .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); - if (endpointFromOverrides.isPresent()) { - return endpointFromOverrides.get(); + .profileName(c.get(SdkClientOption.PROFILE_NAME)).resolveFromOverrides(); + if (overrideEndpoint.isPresent()) { + return ClientEndpointProvider.create(overrideEndpoint.get(), true); } URI clientEndpointUri = null; Region region = c.get(AwsClientOption.AWS_REGION); @@ -116,9 +116,9 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (SdkClientException e) { - // Endpoint resolution failed. This is expected for services that require request-bound - // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. + } catch (Exception e) { + // Endpoint resolution failed. This is expected for services with required parameters + // beyond region, dualstack, and FIPS. Use a placeholder that will be replaced at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-usePriorKnowledgeForH2-service-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-usePriorKnowledgeForH2-service-client-builder-class.java index 63b4bab902d7..3df3fafc1453 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-usePriorKnowledgeForH2-service-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-h2-usePriorKnowledgeForH2-service-client-builder-class.java @@ -100,13 +100,13 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, c -> { - Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + Optional overrideEndpoint = AwsClientEndpointProvider.builder() .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_H2_SERVICE") .serviceEndpointOverrideSystemProperty("aws.endpointUrlH2").serviceProfileProperty("h2_service") .profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); - if (endpointFromOverrides.isPresent()) { - return endpointFromOverrides.get(); + .profileName(c.get(SdkClientOption.PROFILE_NAME)).resolveFromOverrides(); + if (overrideEndpoint.isPresent()) { + return ClientEndpointProvider.create(overrideEndpoint.get(), true); } URI clientEndpointUri = null; Region region = c.get(AwsClientOption.AWS_REGION); @@ -115,9 +115,9 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (SdkClientException e) { - // Endpoint resolution failed. This is expected for services that require request-bound - // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. + } catch (Exception e) { + // Endpoint resolution failed. This is expected for services with required parameters + // beyond region, dualstack, and FIPS. Use a placeholder that will be replaced at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-multi-auth-sigv4a-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-multi-auth-sigv4a-client-builder-class.java index f28a2af9382d..6bad0e14b113 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-multi-auth-sigv4a-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-multi-auth-sigv4a-client-builder-class.java @@ -100,13 +100,13 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, c -> { - Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + Optional overrideEndpoint = AwsClientEndpointProvider.builder() .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") .serviceProfileProperty("database_service").profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); - if (endpointFromOverrides.isPresent()) { - return endpointFromOverrides.get(); + .profileName(c.get(SdkClientOption.PROFILE_NAME)).resolveFromOverrides(); + if (overrideEndpoint.isPresent()) { + return ClientEndpointProvider.create(overrideEndpoint.get(), true); } URI clientEndpointUri = null; Region region = c.get(AwsClientOption.AWS_REGION); @@ -115,9 +115,9 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (SdkClientException e) { - // Endpoint resolution failed. This is expected for services that require request-bound - // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. + } catch (Exception e) { + // Endpoint resolution failed. This is expected for services with required parameters + // beyond region, dualstack, and FIPS. Use a placeholder that will be replaced at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java index f6e6223c9936..f15531bda1cb 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-ops-client-builder-class.java @@ -110,13 +110,13 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, c -> { - Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + Optional overrideEndpoint = AwsClientEndpointProvider.builder() .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") .serviceProfileProperty("database_service").profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); - if (endpointFromOverrides.isPresent()) { - return endpointFromOverrides.get(); + .profileName(c.get(SdkClientOption.PROFILE_NAME)).resolveFromOverrides(); + if (overrideEndpoint.isPresent()) { + return ClientEndpointProvider.create(overrideEndpoint.get(), true); } URI clientEndpointUri = null; Region region = c.get(AwsClientOption.AWS_REGION); @@ -125,9 +125,9 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (SdkClientException e) { - // Endpoint resolution failed. This is expected for services that require request-bound - // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. + } catch (Exception e) { + // Endpoint resolution failed. This is expected for services with required parameters + // beyond region, dualstack, and FIPS. Use a placeholder that will be replaced at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-service-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-service-client-builder-class.java index a4a01fe92b2d..66c44739a50c 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-service-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-no-auth-service-client-builder-class.java @@ -92,13 +92,13 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, c -> { - Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + Optional overrideEndpoint = AwsClientEndpointProvider.builder() .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_DATABASE_SERVICE") .serviceEndpointOverrideSystemProperty("aws.endpointUrlDatabase") .serviceProfileProperty("database_service").profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); - if (endpointFromOverrides.isPresent()) { - return endpointFromOverrides.get(); + .profileName(c.get(SdkClientOption.PROFILE_NAME)).resolveFromOverrides(); + if (overrideEndpoint.isPresent()) { + return ClientEndpointProvider.create(overrideEndpoint.get(), true); } URI clientEndpointUri = null; Region region = c.get(AwsClientOption.AWS_REGION); @@ -107,9 +107,9 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (SdkClientException e) { - // Endpoint resolution failed. This is expected for services that require request-bound - // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. + } catch (Exception e) { + // Endpoint resolution failed. This is expected for services with required parameters + // beyond region, dualstack, and FIPS. Use a placeholder that will be replaced at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-query-client-builder-class.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-query-client-builder-class.java index bf5ca575cca5..69c84cb46ae9 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-query-client-builder-class.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/builder/test-query-client-builder-class.java @@ -117,13 +117,13 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon builder.lazyOptionIfAbsent( SdkClientOption.CLIENT_ENDPOINT_PROVIDER, c -> { - Optional endpointFromOverrides = AwsClientEndpointProvider.builder() + Optional overrideEndpoint = AwsClientEndpointProvider.builder() .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_QUERY_SERVICE") .serviceEndpointOverrideSystemProperty("aws.endpointUrlQuery") .serviceProfileProperty("query_service").profileFile(c.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(c.get(SdkClientOption.PROFILE_NAME)).buildIfOverridePresent(); - if (endpointFromOverrides.isPresent()) { - return endpointFromOverrides.get(); + .profileName(c.get(SdkClientOption.PROFILE_NAME)).resolveFromOverrides(); + if (overrideEndpoint.isPresent()) { + return ClientEndpointProvider.create(overrideEndpoint.get(), true); } URI clientEndpointUri = null; Region region = c.get(AwsClientOption.AWS_REGION); @@ -134,9 +134,9 @@ protected final SdkClientConfiguration finalizeServiceConfiguration(SdkClientCon Endpoint endpoint = CompletableFutureUtils.joinLikeSync(defaultEndpointProvider().resolveEndpoint( endpointParams)); clientEndpointUri = endpoint.url(); - } catch (SdkClientException e) { - // Endpoint resolution failed. This is expected for services that require request-bound - // params (e.g., S3 bucket). Use a placeholder that will be resolved at request time. + } catch (Exception e) { + // Endpoint resolution failed. This is expected for services with required parameters + // beyond region, dualstack, and FIPS. Use a placeholder that will be replaced at request time. return ClientEndpointProvider.create(URI.create("https://localhost"), false); } if (clientEndpointUri.getHost() == null) { diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java index 609328e1c648..2e660f06ea08 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java @@ -74,10 +74,6 @@ private AwsClientEndpointProvider(Builder builder) { this.clientEndpoint = new Lazy<>(() -> resolveClientEndpoint(new Builder(builder))); } - private AwsClientEndpointProvider(Builder builder, boolean overridesOnly) { - this.clientEndpoint = new Lazy<>(() -> resolveFromOverridesAndEnvironment(new Builder(builder))); - } - public static Builder builder() { return new Builder(); } @@ -99,34 +95,27 @@ public boolean isEndpointOverridden() { return clientEndpoint.getValue().isEndpointOverridden; } - // TODO: Remove once all callers are migrated to use resolveFromOverridesAndEnvironment - private ClientEndpoint resolveClientEndpoint(Builder builder) { + // TODO: Remove once all callers are migrated to use resolveFromOverrides + private static ClientEndpoint resolveClientEndpoint(Builder builder) { return OptionalUtils.firstPresent(clientEndpointFromClientOverride(builder), () -> clientEndpointFromEnvironment(builder), () -> clientEndpointFromServiceMetadata(builder)) .orElseThrow(AwsClientEndpointProvider::failToLoadEndpointException); } - private ClientEndpoint resolveFromOverridesAndEnvironment(Builder builder) { - initializeProfileFileDefaults(builder); - return OptionalUtils.firstPresent(clientEndpointFromClientOverride(builder), - () -> clientEndpointFromEnvironment(builder)) - .orElse(null); - } - private static SdkClientException failToLoadEndpointException() { return SdkClientException.create("Unable to determine the default client endpoint. Enable TRACE logging on " + AwsClientEndpointProvider.class.getName() + " for more information."); } - private Optional clientEndpointFromClientOverride(Builder builder) { + private static Optional clientEndpointFromClientOverride(Builder builder) { Optional result = Optional.ofNullable(builder.clientEndpointOverride) .map(uri -> new ClientEndpoint(uri, true)); result.ifPresent(e -> log.trace(() -> "Client was configured with endpoint override: " + e.clientEndpoint)); return result; } - private Optional clientEndpointFromEnvironment(Builder builder) { + private static Optional clientEndpointFromEnvironment(Builder builder) { if (builder.serviceEndpointOverrideEnvironmentVariable == null || builder.serviceEndpointOverrideSystemProperty == null || builder.serviceProfileProperty == null) { @@ -159,19 +148,19 @@ private Optional clientEndpointFromEnvironment(Builder builder) .map(uri -> new ClientEndpoint(uri, true)); } - private Optional systemProperty(String systemProperty) { + private static Optional systemProperty(String systemProperty) { // CHECKSTYLE:OFF - We have to read system properties directly here to match the load order of the other SDKs return createUri("system property " + systemProperty, Optional.ofNullable(System.getProperty(systemProperty))); // CHECKSTYLE:ON } - private Optional environmentVariable(String environmentVariable) { + private static Optional environmentVariable(String environmentVariable) { return createUri("environment variable " + environmentVariable, SystemSettingUtils.resolveEnvironmentVariable(environmentVariable)); } - private Optional profileProperty(Builder builder, String profileProperty) { + private static Optional profileProperty(Builder builder, String profileProperty) { initializeProfileFileDefaults(builder); return createUri("profile property " + profileProperty, Optional.ofNullable(builder.profileFile.get()) @@ -179,7 +168,7 @@ private Optional profileProperty(Builder builder, String profileProperty) { .flatMap(p -> p.property(profileProperty))); } - private Optional servicesProperty(Builder builder) { + private static Optional servicesProperty(Builder builder) { Optional profileFile = Optional.ofNullable(builder.profileFile.get()); Optional servicesSectionName = profileFile .flatMap(pf -> pf.profile(builder.profileName)) @@ -193,7 +182,7 @@ private Optional servicesProperty(Builder builder) { return createUri("services section property", serviceEndpoint); } - private Optional clientEndpointFromServiceMetadata(Builder builder) { + private static Optional clientEndpointFromServiceMetadata(Builder builder) { // This value is generally overridden after endpoints 2.0. It seems to exist for backwards-compatibility // with older client versions or interceptors. @@ -270,7 +259,7 @@ private Optional clientEndpointFromServiceMetadata(Builder build return Optional.of(new ClientEndpoint(endpoint, false)); } - private Optional createUri(String source, Optional uri) { + private static Optional createUri(String source, Optional uri) { return uri.map(u -> { try { URI parsedUri = SdkUri.getInstance().newUri(uri.get()); @@ -282,7 +271,7 @@ private Optional createUri(String source, Optional uri) { }); } - private void initializeProfileFileDefaults(Builder builder) { + private static void initializeProfileFileDefaults(Builder builder) { if (builder.profileFile == null) { builder.profileFile = new Lazy<>(ProfileFile::defaultProfileFile)::getValue; } @@ -496,15 +485,17 @@ public AwsClientEndpointProvider build() { } /** - * Build a {@link ClientEndpointProvider} if an endpoint override or environment-based endpoint is configured. - * Returns {@link Optional#empty()} if no override is found, allowing callers to provide their own fallback. + * Resolve an endpoint from overrides and environment configuration. + * Checks client override, system properties, environment variables, and profile configuration. + * Returns {@link Optional#empty()} if no override is configured, allowing callers to provide + * their own fallback. */ - public Optional buildIfOverridePresent() { - AwsClientEndpointProvider provider = new AwsClientEndpointProvider(this, true); - if (provider.clientEndpoint.getValue() == null) { - return Optional.empty(); - } - return Optional.of(provider); + public Optional resolveFromOverrides() { + Builder copy = new Builder(this); + initializeProfileFileDefaults(copy); + return OptionalUtils.firstPresent(clientEndpointFromClientOverride(copy), + () -> clientEndpointFromEnvironment(copy)) + .map(endpoint -> endpoint.clientEndpoint); } } } diff --git a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProviderBuildIfOverridePresentTest.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProviderResolveFromOverridesTest.java similarity index 51% rename from core/aws-core/src/test/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProviderBuildIfOverridePresentTest.java rename to core/aws-core/src/test/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProviderResolveFromOverridesTest.java index 0ce987e7b71b..8ca96cf9aefb 100644 --- a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProviderBuildIfOverridePresentTest.java +++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProviderResolveFromOverridesTest.java @@ -21,9 +21,8 @@ import java.util.Optional; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; -import software.amazon.awssdk.core.ClientEndpointProvider; -class AwsClientEndpointProviderBuildIfOverridePresentTest { +class AwsClientEndpointProviderResolveFromOverridesTest { private static final String TEST_SYSTEM_PROPERTY = "aws.endpointUrlTestService"; @@ -33,62 +32,48 @@ void cleanup() { } @Test - void buildIfOverridePresent_withClientEndpointOverride_returnsProviderWithOverride() { + void resolveFromOverrides_withClientEndpointOverride_returnsOverrideUri() { URI override = URI.create("https://custom-endpoint.example.com"); - Optional result = AwsClientEndpointProvider.builder() + Optional result = AwsClientEndpointProvider.builder() .clientEndpointOverride(override) - .buildIfOverridePresent(); + .resolveFromOverrides(); assertThat(result).isPresent(); - assertThat(result.get().clientEndpoint()).isEqualTo(override); - assertThat(result.get().isEndpointOverridden()).isTrue(); + assertThat(result.get()).isEqualTo(override); } @Test - void buildIfOverridePresent_withSystemPropertyEndpoint_returnsProviderWithEndpoint() { + void resolveFromOverrides_withSystemPropertyEndpoint_returnsEndpointUri() { System.setProperty(TEST_SYSTEM_PROPERTY, "https://sys-prop-endpoint.example.com"); - Optional result = AwsClientEndpointProvider.builder() + Optional result = AwsClientEndpointProvider.builder() .serviceEndpointOverrideSystemProperty(TEST_SYSTEM_PROPERTY) .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_TEST_SERVICE") .serviceProfileProperty("testservice") - .buildIfOverridePresent(); + .resolveFromOverrides(); assertThat(result).isPresent(); - assertThat(result.get().clientEndpoint()) - .isEqualTo(URI.create("https://sys-prop-endpoint.example.com")); - assertThat(result.get().isEndpointOverridden()).isTrue(); + assertThat(result.get()).isEqualTo(URI.create("https://sys-prop-endpoint.example.com")); } @Test - void buildIfOverridePresent_withNoOverrideOrEnvironment_returnsEmpty() { - Optional result = AwsClientEndpointProvider.builder() + void resolveFromOverrides_withNoOverrideOrEnvironment_returnsEmpty() { + Optional result = AwsClientEndpointProvider.builder() .serviceEndpointOverrideSystemProperty("aws.endpointUrlNonExistent") .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_NON_EXISTENT") .serviceProfileProperty("nonexistent") - .buildIfOverridePresent(); + .resolveFromOverrides(); assertThat(result).isEmpty(); } @Test - void buildIfOverridePresent_withNoParamsConfigured_returnsEmpty() { - Optional result = AwsClientEndpointProvider.builder() - .buildIfOverridePresent(); + void resolveFromOverrides_withNoParamsConfigured_returnsEmpty() { + Optional result = AwsClientEndpointProvider.builder() + .resolveFromOverrides(); assertThat(result).isEmpty(); } - @Test - void buildIfOverridePresent_withoutServiceMetadataParams_returnsProviderWithOverride() { - URI override = URI.create("https://override.example.com"); - - Optional result = AwsClientEndpointProvider.builder() - .clientEndpointOverride(override) - .buildIfOverridePresent(); - - assertThat(result).isPresent(); - assertThat(result.get().clientEndpoint()).isEqualTo(override); - } } diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/endpointproviders/ClientEndpointResolutionTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/endpointproviders/ClientEndpointResolutionTest.java new file mode 100644 index 000000000000..da9e0b3e34d0 --- /dev/null +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/endpointproviders/ClientEndpointResolutionTest.java @@ -0,0 +1,111 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.services.endpointproviders; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.net.URI; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.EndpointCapturingInterceptor; +import software.amazon.awssdk.services.restjsonendpointproviders.RestJsonEndpointProvidersClient; + +/** + * Tests that the generated client builder resolves a default endpoint when no override is configured, + * and correctly uses endpoint overrides from client configuration, system properties, and environment sources. + */ +public class ClientEndpointResolutionTest { + + private static final String SERVICE_SYSTEM_PROPERTY = "aws.endpointUrlRestJsonEndpointProviders"; + + @AfterEach + void cleanup() { + System.clearProperty(SERVICE_SYSTEM_PROPERTY); + } + + @Test + void clientBuild_withRegionOnly_resolvesEndpointViaEndpoints2() { + EndpointCapturingInterceptor interceptor = new EndpointCapturingInterceptor(); + + RestJsonEndpointProvidersClient client = RestJsonEndpointProvidersClient.builder() + .region(Region.US_WEST_2) + .credentialsProvider(AnonymousCredentialsProvider.create()) + .overrideConfiguration(c -> c.addExecutionInterceptor(interceptor)) + .build(); + + try { + client.operationWithNoInputOrOutput(r -> {}); + } catch (EndpointCapturingInterceptor.CaptureCompletedException e) { + // Expected + } + + assertThat(interceptor.endpoints()) + .singleElement() + .asString() + .contains("us-west-2") + .contains("amazonaws.com"); + } + + @Test + void clientBuild_withSystemPropertyOverride_usesOverrideEndpoint() { + System.setProperty(SERVICE_SYSTEM_PROPERTY, "https://custom-override.example.com"); + + EndpointCapturingInterceptor interceptor = new EndpointCapturingInterceptor(); + + RestJsonEndpointProvidersClient client = RestJsonEndpointProvidersClient.builder() + .region(Region.US_WEST_2) + .credentialsProvider(AnonymousCredentialsProvider.create()) + .overrideConfiguration(c -> c.addExecutionInterceptor(interceptor)) + .build(); + + try { + client.operationWithNoInputOrOutput(r -> {}); + } catch (EndpointCapturingInterceptor.CaptureCompletedException e) { + // Expected + } + + assertThat(interceptor.endpoints()) + .singleElement() + .asString() + .startsWith("https://custom-override.example.com"); + } + + @Test + void clientBuild_withEndpointOverride_usesClientOverride() { + EndpointCapturingInterceptor interceptor = new EndpointCapturingInterceptor(); + + RestJsonEndpointProvidersClient client = RestJsonEndpointProvidersClient.builder() + .region(Region.US_WEST_2) + .endpointOverride(URI.create("https://my-override.example.com")) + .credentialsProvider(AnonymousCredentialsProvider.create()) + .overrideConfiguration(c -> c.addExecutionInterceptor(interceptor)) + .build(); + + try { + client.operationWithNoInputOrOutput(r -> {}); + } catch (EndpointCapturingInterceptor.CaptureCompletedException e) { + // Expected + } + + assertThat(interceptor.endpoints()) + .singleElement() + .asString() + .startsWith("https://my-override.example.com"); + } + +}