From ba9683c0fd303df512c4707af2229eb1ce7bbe8b Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Tue, 18 Aug 2026 12:15:49 -0700 Subject: [PATCH] Add @SdkAdvancedApi annotation to event stream operation handlers --- ...documentation-AWSSDKforJavav2-2de77ee.json | 6 ++++++ ...amResponseHandlerBuilderInterfaceSpec.java | 6 ++++-- .../EventStreamResponseHandlerSpec.java | 19 +++++++++++++++++++ .../eventstream/test-response-handler.java | 12 ++++++++++-- 4 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 .changes/next-release/documentation-AWSSDKforJavav2-2de77ee.json diff --git a/.changes/next-release/documentation-AWSSDKforJavav2-2de77ee.json b/.changes/next-release/documentation-AWSSDKforJavav2-2de77ee.json new file mode 100644 index 000000000000..313f4eab51f4 --- /dev/null +++ b/.changes/next-release/documentation-AWSSDKforJavav2-2de77ee.json @@ -0,0 +1,6 @@ +{ + "type": "documentation", + "category": "AWS SDK for Java v2", + "contributor": "", + "description": "Add the @SdkAdvancedApi annotation to generated, operation event stream response handlers." +} diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/eventstream/EventStreamResponseHandlerBuilderInterfaceSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/eventstream/EventStreamResponseHandlerBuilderInterfaceSpec.java index 0d8685ef4227..f05a0638a327 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/eventstream/EventStreamResponseHandlerBuilderInterfaceSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/eventstream/EventStreamResponseHandlerBuilderInterfaceSpec.java @@ -67,8 +67,10 @@ protected TypeSpec.Builder createTypeSpecBuilder() { return PoetUtils.createInterfaceBuilder(className()).addModifiers(Modifier.PUBLIC, Modifier.STATIC) .addJavadoc("Builder for {@link $1T}. This can be used to create the {@link $1T} in a more " - + "functional way, you may also directly implement the {@link $1T} interface if " - + "preferred.", + + "functional way. Directly implementing the {@link $1T} interface is possible but " + + "requires subscribing to the event publisher, requesting data via the Subscription, " + + "resetting state on retry, and freeing resources on error; the builder handles all " + + "of this automatically.", responseHandlerType) .addSuperinterface(superBuilderInterface); } diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/eventstream/EventStreamResponseHandlerSpec.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/eventstream/EventStreamResponseHandlerSpec.java index 8fa6aaa29a96..9560d97e6a30 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/eventstream/EventStreamResponseHandlerSpec.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/eventstream/EventStreamResponseHandlerSpec.java @@ -15,11 +15,13 @@ package software.amazon.awssdk.codegen.poet.eventstream; +import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeSpec; import javax.lang.model.element.Modifier; +import software.amazon.awssdk.annotations.SdkAdvancedApi; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.awscore.eventstream.EventStreamResponseHandler; import software.amazon.awssdk.codegen.emitters.GeneratorTaskParams; @@ -60,6 +62,7 @@ public TypeSpec poetSpec() { return PoetUtils.createInterfaceBuilder(className()) .addModifiers(Modifier.PUBLIC) .addAnnotation(SdkPublicApi.class) + .addAnnotation(advancedApiAnnotation()) .addSuperinterface(superResponseHandlerInterface) .addJavadoc("Response handler for the $L API.", apiName) .addMethod(builderMethodSpec()) @@ -68,6 +71,22 @@ public TypeSpec poetSpec() { .build(); } + private AnnotationSpec advancedApiAnnotation() { + return AnnotationSpec.builder(SdkAdvancedApi.class) + .addMember("cautionWhen", "$T.$L", SdkAdvancedApi.Usage.class, "IMPLEMENTED") + .addMember("guidance", "$S", + "onEventStream() receives a reactive-streams Publisher; the implementation must " + + "subscribe to it and call Subscription.request(n) to pull events -- a handler " + + "that never subscribes or never requests stalls the stream and hangs the " + + "operation. On retry the SDK calls onEventStream() again with a new Publisher; " + + "the implementation must reset accumulated state or throw to refuse the retry. " + + "Free resources in exceptionOccurred().") + .addMember("saferAlternative", "$S", + "Prefer the generated builder() with subscriber(Consumer) or subscriber(Visitor) " + + "which handle subscription, backpressure, and retry-state reset automatically.") + .build(); + } + @Override public ClassName className() { return poetExt.eventStreamResponseHandlerType(operationModel); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/eventstream/test-response-handler.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/eventstream/test-response-handler.java index a3f53ee99da6..20f17040879b 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/eventstream/test-response-handler.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/eventstream/test-response-handler.java @@ -2,6 +2,7 @@ import java.util.function.Consumer; import software.amazon.awssdk.annotations.Generated; +import software.amazon.awssdk.annotations.SdkAdvancedApi; import software.amazon.awssdk.annotations.SdkPublicApi; import software.amazon.awssdk.awscore.eventstream.EventStreamResponseHandler; @@ -10,6 +11,11 @@ */ @Generated("software.amazon.awssdk:codegen") @SdkPublicApi +@SdkAdvancedApi( + cautionWhen = SdkAdvancedApi.Usage.IMPLEMENTED, + guidance = "onEventStream() receives a reactive-streams Publisher; the implementation must subscribe to it and call Subscription.request(n) to pull events -- a handler that never subscribes or never requests stalls the stream and hangs the operation. On retry the SDK calls onEventStream() again with a new Publisher; the implementation must reset accumulated state or throw to refuse the retry. Free resources in exceptionOccurred().", + saferAlternative = "Prefer the generated builder() with subscriber(Consumer) or subscriber(Visitor) which handle subscription, backpressure, and retry-state reset automatically." +) public interface EventStreamOperationResponseHandler extends EventStreamResponseHandler { /** @@ -21,8 +27,10 @@ static Builder builder() { /** * Builder for {@link EventStreamOperationResponseHandler}. This can be used to create the - * {@link EventStreamOperationResponseHandler} in a more functional way, you may also directly implement the - * {@link EventStreamOperationResponseHandler} interface if preferred. + * {@link EventStreamOperationResponseHandler} in a more functional way. Directly implementing the + * {@link EventStreamOperationResponseHandler} interface is possible but requires subscribing to the event + * publisher, requesting data via the Subscription, resetting state on retry, and freeing resources on error; the + * builder handles all of this automatically. */ @Generated("software.amazon.awssdk:codegen") interface Builder extends EventStreamResponseHandler.Builder {