Skip to content

Add useragent for service and version #6212

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jul 1, 2025
6 changes: 6 additions & 0 deletions .changes/next-release/feature-AWSSDKforJavav2-e1e404e.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "feature",
"category": "AWS SDK for Java v2",
"contributor": "",
"description": "Add the sdk service client version to the useragent"
}
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,14 @@ private MethodSpec constructor(TypeSpec.Builder classBuilder) {
.addStatement("this.clientHandler = new $T(clientConfiguration)", AwsAsyncClientHandler.class)
.addStatement("this.clientConfiguration = clientConfiguration.toBuilder()"
+ ".option($T.SDK_CLIENT, this)"
+ ".build()", SdkClientOption.class);
+ ".option($T.API_METADATA, $S + \"#\" + $T.VERSION)"
+ ".build()",
SdkClientOption.class,
SdkClientOption.class,
transformServiceId(model.getMetadata().getServiceId()),
ClassName.get(model.getMetadata().getFullClientInternalPackageName(),
"ServiceVersionInfo"));

FieldSpec protocolFactoryField = protocolSpec.protocolFactory(model);
if (model.getMetadata().isJsonProtocol()) {
builder.addStatement("this.$N = init($T.builder()).build()", protocolFactoryField.name,
Expand Down Expand Up @@ -283,6 +290,11 @@ private boolean hasOperationWithEventStreamOutput() {
return model.getOperations().values().stream().anyMatch(OperationModel::hasEventStreamOutput);
}

private String transformServiceId(String serviceId) {
// According to User Agent 2.0 spec, replace spaces with underscores
return serviceId.replace(" ", "_");
}

private MethodSpec nameMethod() {
return MethodSpec.methodBuilder("serviceName")
.addAnnotation(Override.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,13 @@ private MethodSpec constructor() {
.addStatement("this.clientHandler = new $T(clientConfiguration)", protocolSpec.getClientHandlerClass())
.addStatement("this.clientConfiguration = clientConfiguration.toBuilder()"
+ ".option($T.SDK_CLIENT, this)"
+ ".build()", SdkClientOption.class);
+ ".option($T.API_METADATA, $S + \"#\" + $T.VERSION)"
+ ".build()",
SdkClientOption.class,
SdkClientOption.class,
transformServiceId(model.getMetadata().getServiceId()),
ClassName.get(model.getMetadata().getFullClientInternalPackageName(),
"ServiceVersionInfo"));

FieldSpec protocolFactoryField = protocolSpec.protocolFactory(model);
if (model.getMetadata().isJsonProtocol()) {
Expand Down Expand Up @@ -249,6 +255,11 @@ private Stream<MethodSpec> operations(OperationModel opModel) {
return methods.stream();
}

private String transformServiceId(String serviceId) {
// According to User Agent 2.0 spec, replace spaces with underscores
return serviceId.replace(" ", "_");
}

private MethodSpec traditionalMethod(OperationModel opModel) {
MethodSpec.Builder method = SyncClientInterface.operationMethodSignature(model, opModel)
.addAnnotation(Override.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,27 @@
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import javax.lang.model.element.Modifier;
import software.amazon.awssdk.annotations.SdkInternalApi;
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
import software.amazon.awssdk.codegen.poet.ClassSpec;
import software.amazon.awssdk.codegen.poet.PoetExtension;
import software.amazon.awssdk.codegen.poet.PoetUtils;

public class ServiceVersionInfoSpec implements ClassSpec {
private final PoetExtension poetExtension;
private final IntermediateModel model;

public ServiceVersionInfoSpec(IntermediateModel model) {
this.poetExtension = new PoetExtension(model);
this.model = model;
}

@Override
public TypeSpec poetSpec() {
TypeSpec.Builder builder = TypeSpec.classBuilder("ServiceVersionInfo")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addAnnotation(PoetUtils.generatedAnnotation())
.addAnnotation(SdkInternalApi.class)
.addField(FieldSpec.builder(
String.class, "VERSION", Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
.initializer("$S", SDK_VERSION)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,17 @@
public class ServiceVersionInfoSpecTest {

// Fixture test that compares generated ServiceVersionInfo class against expected output.
// The fixture file uses {{VERSION}} as a placeholder which gets replaced with the current
// SDK version at test time, since the generated code injects the actual version at build time.
// The fixture file uses {{VERSION}} as a placeholder for the SDK version. The placeholder get
// replaced with actual value at test time, since the generated code injects the actual
// version at build time.
@Test
void testServiceVersionInfoClass() {
String currVersion = VersionInfo.SDK_VERSION;
ClassSpec serviceVersionInfoSpec = new ServiceVersionInfoSpec(ClientTestModels.restJsonServiceModels());

String expectedContent = loadFixtureFile("test-service-version-info-class.java");
expectedContent = expectedContent.replace("{{VERSION}}", currVersion);
expectedContent = expectedContent
.replace("{{VERSION}}", currVersion);

String actualContent = generateContent(serviceVersionInfoSpec);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import java.lang.String;
import software.amazon.awssdk.annotations.Generated;
import software.amazon.awssdk.annotations.SdkInternalApi;

@Generated("software.amazon.awssdk:codegen")
@SdkInternalApi
public final class ServiceVersionInfo {
/**
* Returns the current version for the AWS SDK in which this class is running.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import software.amazon.awssdk.protocols.json.JsonOperationMetadata;
import software.amazon.awssdk.retries.api.RetryStrategy;
import software.amazon.awssdk.services.json.internal.JsonServiceClientConfigurationBuilder;
import software.amazon.awssdk.services.json.internal.ServiceVersionInfo;
import software.amazon.awssdk.services.json.model.APostOperationRequest;
import software.amazon.awssdk.services.json.model.APostOperationResponse;
import software.amazon.awssdk.services.json.model.APostOperationWithOutputRequest;
Expand Down Expand Up @@ -140,7 +141,8 @@ final class DefaultJsonAsyncClient implements JsonAsyncClient {

protected DefaultJsonAsyncClient(SdkClientConfiguration clientConfiguration) {
this.clientHandler = new AwsAsyncClientHandler(clientConfiguration);
this.clientConfiguration = clientConfiguration.toBuilder().option(SdkClientOption.SDK_CLIENT, this).build();
this.clientConfiguration = clientConfiguration.toBuilder().option(SdkClientOption.SDK_CLIENT, this)
.option(SdkClientOption.API_METADATA, "Json_Service" + "#" + ServiceVersionInfo.VERSION).build();
this.protocolFactory = init(AwsJsonProtocolFactory.builder()).build();
this.executor = clientConfiguration.option(SdkAdvancedAsyncClientOption.FUTURE_COMPLETION_EXECUTOR);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
import software.amazon.awssdk.protocols.json.JsonOperationMetadata;
import software.amazon.awssdk.retries.api.RetryStrategy;
import software.amazon.awssdk.services.json.internal.JsonServiceClientConfigurationBuilder;
import software.amazon.awssdk.services.json.internal.ServiceVersionInfo;
import software.amazon.awssdk.services.json.model.APostOperationRequest;
import software.amazon.awssdk.services.json.model.APostOperationResponse;
import software.amazon.awssdk.services.json.model.APostOperationWithOutputRequest;
Expand Down Expand Up @@ -143,7 +144,9 @@ final class DefaultJsonAsyncClient implements JsonAsyncClient {

protected DefaultJsonAsyncClient(SdkClientConfiguration clientConfiguration) {
this.clientHandler = new AwsAsyncClientHandler(clientConfiguration);
this.clientConfiguration = clientConfiguration.toBuilder().option(SdkClientOption.SDK_CLIENT, this).build();
this.clientConfiguration = clientConfiguration.toBuilder().option(SdkClientOption.SDK_CLIENT, this)
.option(SdkClientOption.API_METADATA,
"Json_Service" + "#" + ServiceVersionInfo.VERSION).build();
this.protocolFactory = init(AwsCborProtocolFactory.builder()).build();
this.jsonProtocolFactory = init(AwsJsonProtocolFactory.builder()).build();
this.executor = clientConfiguration.option(SdkAdvancedAsyncClientOption.FUTURE_COMPLETION_EXECUTOR);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
import software.amazon.awssdk.retries.api.RetryStrategy;
import software.amazon.awssdk.services.json.batchmanager.JsonAsyncBatchManager;
import software.amazon.awssdk.services.json.internal.JsonServiceClientConfigurationBuilder;
import software.amazon.awssdk.services.json.internal.ServiceVersionInfo;
import software.amazon.awssdk.services.json.model.APostOperationRequest;
import software.amazon.awssdk.services.json.model.APostOperationResponse;
import software.amazon.awssdk.services.json.model.APostOperationWithOutputRequest;
Expand Down Expand Up @@ -153,7 +154,9 @@ final class DefaultJsonAsyncClient implements JsonAsyncClient {

protected DefaultJsonAsyncClient(SdkClientConfiguration clientConfiguration) {
this.clientHandler = new AwsAsyncClientHandler(clientConfiguration);
this.clientConfiguration = clientConfiguration.toBuilder().option(SdkClientOption.SDK_CLIENT, this).build();
this.clientConfiguration = clientConfiguration.toBuilder().option(SdkClientOption.SDK_CLIENT, this)
.option(SdkClientOption.API_METADATA,
"Json_Service" + "#" + ServiceVersionInfo.VERSION).build();
this.protocolFactory = init(AwsJsonProtocolFactory.builder()).build();
this.executor = clientConfiguration.option(SdkAdvancedAsyncClientOption.FUTURE_COMPLETION_EXECUTOR);
this.executorService = clientConfiguration.option(SdkClientOption.SCHEDULED_EXECUTOR_SERVICE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import software.amazon.awssdk.protocols.json.JsonOperationMetadata;
import software.amazon.awssdk.retries.api.RetryStrategy;
import software.amazon.awssdk.services.json.internal.JsonServiceClientConfigurationBuilder;
import software.amazon.awssdk.services.json.internal.ServiceVersionInfo;
import software.amazon.awssdk.services.json.model.APostOperationRequest;
import software.amazon.awssdk.services.json.model.APostOperationResponse;
import software.amazon.awssdk.services.json.model.APostOperationWithOutputRequest;
Expand Down Expand Up @@ -108,7 +109,8 @@ final class DefaultJsonClient implements JsonClient {

protected DefaultJsonClient(SdkClientConfiguration clientConfiguration) {
this.clientHandler = new AwsSyncClientHandler(clientConfiguration);
this.clientConfiguration = clientConfiguration.toBuilder().option(SdkClientOption.SDK_CLIENT, this).build();
this.clientConfiguration = clientConfiguration.toBuilder().option(SdkClientOption.SDK_CLIENT, this)
.option(SdkClientOption.API_METADATA, "Json_Service" + "#" + ServiceVersionInfo.VERSION).build();
this.protocolFactory = init(AwsJsonProtocolFactory.builder()).build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import software.amazon.awssdk.protocols.query.AwsQueryProtocolFactory;
import software.amazon.awssdk.retries.api.RetryStrategy;
import software.amazon.awssdk.services.query.internal.QueryServiceClientConfigurationBuilder;
import software.amazon.awssdk.services.query.internal.ServiceVersionInfo;
import software.amazon.awssdk.services.query.model.APostOperationRequest;
import software.amazon.awssdk.services.query.model.APostOperationResponse;
import software.amazon.awssdk.services.query.model.APostOperationWithOutputRequest;
Expand Down Expand Up @@ -122,7 +123,8 @@ final class DefaultQueryAsyncClient implements QueryAsyncClient {

protected DefaultQueryAsyncClient(SdkClientConfiguration clientConfiguration) {
this.clientHandler = new AwsAsyncClientHandler(clientConfiguration);
this.clientConfiguration = clientConfiguration.toBuilder().option(SdkClientOption.SDK_CLIENT, this).build();
this.clientConfiguration = clientConfiguration.toBuilder().option(SdkClientOption.SDK_CLIENT, this)
.option(SdkClientOption.API_METADATA, "Query_Service" + "#" + ServiceVersionInfo.VERSION).build();
this.protocolFactory = init();
this.executorService = clientConfiguration.option(SdkClientOption.SCHEDULED_EXECUTOR_SERVICE);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import software.amazon.awssdk.protocols.query.AwsQueryProtocolFactory;
import software.amazon.awssdk.retries.api.RetryStrategy;
import software.amazon.awssdk.services.query.internal.QueryServiceClientConfigurationBuilder;
import software.amazon.awssdk.services.query.internal.ServiceVersionInfo;
import software.amazon.awssdk.services.query.model.APostOperationRequest;
import software.amazon.awssdk.services.query.model.APostOperationResponse;
import software.amazon.awssdk.services.query.model.APostOperationWithOutputRequest;
Expand Down Expand Up @@ -113,7 +114,8 @@ final class DefaultQueryClient implements QueryClient {

protected DefaultQueryClient(SdkClientConfiguration clientConfiguration) {
this.clientHandler = new AwsSyncClientHandler(clientConfiguration);
this.clientConfiguration = clientConfiguration.toBuilder().option(SdkClientOption.SDK_CLIENT, this).build();
this.clientConfiguration = clientConfiguration.toBuilder().option(SdkClientOption.SDK_CLIENT, this)
.option(SdkClientOption.API_METADATA, "Query_Service" + "#" + ServiceVersionInfo.VERSION).build();
this.protocolFactory = init();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import software.amazon.awssdk.protocols.xml.AwsXmlProtocolFactory;
import software.amazon.awssdk.protocols.xml.XmlOperationMetadata;
import software.amazon.awssdk.retries.api.RetryStrategy;
import software.amazon.awssdk.services.xml.internal.ServiceVersionInfo;
import software.amazon.awssdk.services.xml.internal.XmlServiceClientConfigurationBuilder;
import software.amazon.awssdk.services.xml.model.APostOperationRequest;
import software.amazon.awssdk.services.xml.model.APostOperationResponse;
Expand Down Expand Up @@ -114,7 +115,8 @@ final class DefaultXmlAsyncClient implements XmlAsyncClient {

protected DefaultXmlAsyncClient(SdkClientConfiguration clientConfiguration) {
this.clientHandler = new AwsAsyncClientHandler(clientConfiguration);
this.clientConfiguration = clientConfiguration.toBuilder().option(SdkClientOption.SDK_CLIENT, this).build();
this.clientConfiguration = clientConfiguration.toBuilder().option(SdkClientOption.SDK_CLIENT, this)
.option(SdkClientOption.API_METADATA, "Xml_Service" + "#" + ServiceVersionInfo.VERSION).build();
this.protocolFactory = init();
this.executor = clientConfiguration.option(SdkAdvancedAsyncClientOption.FUTURE_COMPLETION_EXECUTOR);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import software.amazon.awssdk.protocols.xml.AwsXmlProtocolFactory;
import software.amazon.awssdk.protocols.xml.XmlOperationMetadata;
import software.amazon.awssdk.retries.api.RetryStrategy;
import software.amazon.awssdk.services.xml.internal.ServiceVersionInfo;
import software.amazon.awssdk.services.xml.internal.XmlServiceClientConfigurationBuilder;
import software.amazon.awssdk.services.xml.model.APostOperationRequest;
import software.amazon.awssdk.services.xml.model.APostOperationResponse;
Expand Down Expand Up @@ -95,7 +96,8 @@ final class DefaultXmlClient implements XmlClient {

protected DefaultXmlClient(SdkClientConfiguration clientConfiguration) {
this.clientHandler = new AwsSyncClientHandler(clientConfiguration);
this.clientConfiguration = clientConfiguration.toBuilder().option(SdkClientOption.SDK_CLIENT, this).build();
this.clientConfiguration = clientConfiguration.toBuilder().option(SdkClientOption.SDK_CLIENT, this)
.option(SdkClientOption.API_METADATA, "Xml_Service" + "#" + ServiceVersionInfo.VERSION).build();
this.protocolFactory = init();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import software.amazon.awssdk.protocols.json.JsonOperationMetadata;
import software.amazon.awssdk.retries.api.RetryStrategy;
import software.amazon.awssdk.services.json.internal.JsonServiceClientConfigurationBuilder;
import software.amazon.awssdk.services.json.internal.ServiceVersionInfo;
import software.amazon.awssdk.services.json.model.APostOperationRequest;
import software.amazon.awssdk.services.json.model.APostOperationResponse;
import software.amazon.awssdk.services.json.model.APostOperationWithOutputRequest;
Expand Down Expand Up @@ -146,7 +147,8 @@ final class DefaultJsonAsyncClient implements JsonAsyncClient {

protected DefaultJsonAsyncClient(SdkClientConfiguration clientConfiguration) {
this.clientHandler = new AwsAsyncClientHandler(clientConfiguration);
this.clientConfiguration = clientConfiguration.toBuilder().option(SdkClientOption.SDK_CLIENT, this).build();
this.clientConfiguration = clientConfiguration.toBuilder().option(SdkClientOption.SDK_CLIENT, this)
.option(SdkClientOption.API_METADATA, "Json_Service" + "#" + ServiceVersionInfo.VERSION).build();
this.protocolFactory = init(AwsJsonProtocolFactory.builder()).build();
this.executor = clientConfiguration.option(SdkAdvancedAsyncClientOption.FUTURE_COMPLETION_EXECUTOR);
}
Expand Down
Loading
Loading