AWS Security ChangesHomeSearch

AWS powertools documentation change

Service: powertools · 2025-11-16 · Documentation low

File: powertools/java/latest/utilities/idempotency.md

Summary

Updated documentation for Java idempotency utility including version bump to 2.7.0, added functional API examples, clarified DynamoDB usage patterns, and expanded configuration options

Security assessment

Changes focus on feature enhancements (functional API support, generic types) and documentation improvements. No direct evidence of security vulnerability fixes or new security-related documentation. Version update from 2.5.0 to 2.7.0 might include security patches, but the diff doesn't explicitly mention any security fixes.

Diff

diff --git a/powertools/java/latest/utilities/idempotency.md b/powertools/java/latest/utilities/idempotency.md
index a212ed250..986774559 100644
--- a//powertools/java/latest/utilities/idempotency.md
+++ b//powertools/java/latest/utilities/idempotency.md
@@ -22,0 +23 @@ Initializing search
+  * [ Usage patterns  ](../../usage-patterns/)
@@ -38,2 +39,2 @@ Initializing search
-        * Idempotent annotation 
-          * Idempotent annotation on another method 
+        * Basic usage 
+          * Making non-handler methods idempotent 
@@ -47,0 +49,2 @@ Initializing search
+        * Using explicit function names 
+        * Generic return types support 
@@ -90,2 +93,2 @@ Table of contents
-    * Idempotent annotation 
-      * Idempotent annotation on another method 
+    * Basic usage 
+      * Making non-handler methods idempotent 
@@ -99,0 +103,2 @@ Table of contents
+    * Using explicit function names 
+    * Generic return types support 
@@ -197,0 +203 @@ MavenGradle
+    49
@@ -207 +213 @@ MavenGradle
-            <version>2.5.0</version>
+            <version>2.7.0</version>
@@ -212,0 +219 @@ MavenGradle
+    <!-- Note: This AspectJ configuration is not needed when using the functional approach -->
@@ -269,0 +277 @@ MavenGradle
+    16
@@ -276 +284 @@ MavenGradle
-            id 'io.freefair.aspectj.post-compile-weaving' version '8.1.0'
+            id 'io.freefair.aspectj.post-compile-weaving' version '8.1.0' // Not needed when using the functional approach
@@ -284 +292,2 @@ MavenGradle
-            aspect 'software.amazon.lambda:powertools-idempotency-dynamodb:2.5.0'
+            aspect 'software.amazon.lambda:powertools-idempotency-core:2.7.0' // Not needed when using the functional approach
+            implementation 'software.amazon.lambda:powertools-idempotency-dynamodb:2.7.0'
@@ -297 +306 @@ Before getting started, you need to create a persistent storage layer where the
-As of now, Amazon DynamoDB is the only supported persistent storage layer, so you'll need to create a table first.
+As of now, Amazon DynamoDB is the only supported persistent storage layer, so you'll need to create a table first or bring your own persistence store.
@@ -376 +385 @@ Warning: Large responses with DynamoDB persistence layer
-When using this utility with DynamoDB, your function's responses must be [smaller than 400KB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Limits.html#limits-items). Larger items cannot be written to DynamoDB and will cause exceptions.
+When using this utility with DynamoDB, your function's responses must be [smaller than 400KB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Constraints.html#limits-items). Larger items cannot be written to DynamoDB and will cause exceptions.
@@ -380 +389 @@ Info: DynamoDB
-Each function invocation will generally make 2 requests to DynamoDB. If the result returned by your Lambda is less than 1kb, you can expect 2 WCUs per invocation. For retried invocations, you will see 1WCU and 1RCU. Review the [DynamoDB pricing documentation](https://aws.amazon.com/dynamodb/pricing/) to estimate the cost.
+Each function invocation will generally make 1 request to DynamoDB. If the result returned by your Lambda is less than 1kb, you can expect 1 WCUs per invocation. For retried invocations, you will see 1 WCU. In some cases, the utility might make 2 requests to DynamoDB in which case you will see 1 RCU and 1 WCU. Review the [DynamoDB pricing documentation](https://aws.amazon.com/dynamodb/pricing/) to estimate the cost.
@@ -382 +391 @@ Each function invocation will generally make 2 requests to DynamoDB. If the resu
-### Idempotent annotation¶
+### Basic usage¶
@@ -384 +393 @@ Each function invocation will generally make 2 requests to DynamoDB. If the resu
-You can quickly start by initializing the `DynamoDBPersistenceStore` and using it with the `@Idempotent` annotation on your Lambda handler.
+You can use Powertools for AWS Lambda Idempotency with either the `@Idempotent` annotation or the functional API.
@@ -390 +399 @@ Initialization and configuration of the `DynamoDBPersistenceStore` must be perfo
-App.javaExample event
+@Idempotent annotationFunctional APIExample event
@@ -421 +430 @@ App.javaExample event
-        // we need to initialize idempotency store before the handleRequest method is called
+        // We need to initialize idempotency store before the handleRequest method is called
@@ -440,0 +450,51 @@ App.javaExample event
+---|---  
+      
+    
+     1
+     2
+     3
+     4
+     5
+     6
+     7
+     8
+     9
+    10
+    11
+    12
+    13
+    14
+    15
+    16
+    17
+    18
+    19
+    20
+    21
+
+| 
+    
+    
+    public class App implements RequestHandler<Subscription, SubscriptionResult> {
+    
+      public App() {
+        // We need to initialize idempotency store before the handleRequest method is called
+        Idempotency.config().withPersistenceStore(
+          DynamoDBPersistenceStore.builder()
+            .withTableName(System.getenv("TABLE_NAME"))
+            .build()
+          ).configure();
+      }
+    
+      public SubscriptionResult handleRequest(final Subscription event, final Context context) {
+        Idempotency.registerLambdaContext(context);
+        return Idempotency.makeIdempotent(this::processSubscription, event, SubscriptionResult.class);
+      }
+    
+      private SubscriptionResult processSubscription(Subscription event) {
+        SubscriptionPayment payment = createSubscriptionPayment(event.getUsername(), event.getProductId());
+        return new SubscriptionResult(payment.getId(), "success", 200);
+      }
+    }
+      
+  
@@ -460 +520 @@ App.javaExample event
-#### Idempotent annotation on another method¶
+#### Making non-handler methods idempotent¶
@@ -462 +522 @@ App.javaExample event
-You can use the `@Idempotent` annotation for any synchronous Java function, not only the `handleRequest` one.
+You can make any synchronous Java function idempotent, not only the `handleRequest` handler.
@@ -464 +524 @@ You can use the `@Idempotent` annotation for any synchronous Java function, not
-When using `@Idempotent` annotation on another method, you must tell which parameter in the method signature has the data we should use:
+**With the`@Idempotent` annotation**, you must specify which parameter contains the idempotency key:
@@ -470,0 +531,7 @@ When using `@Idempotent` annotation on another method, you must tell which param
+**With the functional API** , you explicitly pass the idempotency key:
+
+  * For single-parameter methods, use `Idempotency.makeIdempotent(this::method, param, ReturnType.class)`
+  * For multi-parameter methods, use `Idempotency.makeIdempotent(idempotencyKey, () -> method(param1, param2), ReturnType.class)`
+
+
+
@@ -473 +540 @@ The parameter must be serializable in JSON. We use Jackson internally to (de)ser
-AppSqsEvent.javaBatch event
+@Idempotent annotationFunctional APIBatch event
@@ -477,0 +545,73 @@ This example also demonstrates how you can integrate with [Batch utility](../bat
+     1
+     2
+     3
+     4
+     5
+     6
+     7
+     8
+     9
+    10
+    11
+    12
+    13
+    14
+    15
+    16
+    17
+    18
+    19
+    20
+    21
+    22
+    23
+    24
+    25
+    26
+    27
+    28
+    29
+    30
+    31
+
+| 
+    
+    
+    public class SqsBatchHandler implements RequestHandler<SQSEvent, SQSBatchResponse> {
+    
+      private final BatchMessageHandler<SQSEvent, SQSBatchResponse> handler;
+    
+      public SqsBatchHandler() {
+        Idempotency.config()
+          .withPersistenceStore(
+              DynamoDBPersistenceStore.builder()
+                .withTableName(System.getenv("TABLE_NAME"))
+                .build()
+          ).withConfig(
+               IdempotencyConfig.builder()
+                 .withEventKeyJMESPath("messageId")
+                 .build()
+          ).configure();
+    
+        handler = new BatchMessageHandlerBuilder()
+                .withSqsBatchHandler()
+                .buildWithRawMessageHandler(this::processMessage);
+      }
+    
+      @Override
+      public SQSBatchResponse handleRequest(SQSEvent sqsEvent, Context context) {
+        return handler.processBatch(sqsEvent, context);
+      }
+    
+      @Idempotent
+      private void processMessage(@IdempotencyKey SQSEvent.SQSMessage message) {
+        // Process message
+      }
+    }
+      
+