3030 * <p>This class is thread-safe. All operations delegate to the underlying persistence store
3131 * which handles concurrent access safely.</p>
3232 *
33- * <p>Example usage with Supplier:</p>
33+ * <p><strong>Important:</strong> Always call {@link Idempotency#registerLambdaContext(Context)}
34+ * at the start of your handler to enable proper timeout handling.</p>
35+ *
36+ * <p>Example usage with Function (single parameter):</p>
3437 * <pre>{@code
35- * public List<String> handleRequest(SQSEvent event , Context context) {
38+ * public Basket handleRequest(Product input , Context context) {
3639 * Idempotency.registerLambdaContext(context);
37- * return event.getRecords().stream()
38- * .map(record -> PowertoolsIdempotency.makeIdempotent(
39- * record.getBody(), // used as idempotency key
40- * () -> processPayment(record.getMessageId(), record.getBody())))
41- * .collect(Collectors.toList());
40+ * return PowertoolsIdempotency.makeIdempotent(this::processProduct, input, Basket.class);
41+ * }
42+ *
43+ * private Basket processProduct(Product product) {
44+ * // business logic
4245 * }
4346 * }</pre>
4447 *
45- * <p>Example usage with Function :</p>
48+ * <p>Example usage with Supplier (multi-parameter methods) :</p>
4649 * <pre>{@code
47- * public Basket handleRequest(Product input , Context context) {
50+ * public String handleRequest(SQSEvent event , Context context) {
4851 * Idempotency.registerLambdaContext(context);
49- * return PowertoolsIdempotency.makeIdempotent(this::process, input);
52+ * return PowertoolsIdempotency.makeIdempotent(
53+ * event.getRecords().get(0).getBody(),
54+ * () -> processPayment(orderId, amount, currency),
55+ * String.class
56+ * );
5057 * }
5158 * }</pre>
5259 *
53- * <p>When different methods use the same payload as idempotency key, use
54- * {@link #makeIdempotent(String, Object, Supplier)} with explicit function names
60+ * <p>When different methods use the same payload as idempotency key, use explicit function names
5561 * to differentiate between them:</p>
5662 * <pre>{@code
5763 * // Different methods, same payload
58- * PowertoolsIdempotency.makeIdempotent("processPayment", orderId, () -> processPayment(orderId));
59- * PowertoolsIdempotency.makeIdempotent("refundPayment", orderId, () -> refundPayment(orderId));
64+ * PowertoolsIdempotency.makeIdempotent("processPayment", orderId,
65+ * () -> processPayment(orderId), String.class);
66+ *
67+ * PowertoolsIdempotency.makeIdempotent("refundPayment", orderId,
68+ * () -> refundPayment(orderId), String.class);
6069 * }</pre>
6170 *
6271 * @see Idempotency
63- * @see #makeIdempotent(Object, Supplier)
64- * @see #makeIdempotent(String, Object, Supplier)
65- * @see #makeIdempotent(Function, Object)
72+ * @see #makeIdempotent(Object, Supplier, Class )
73+ * @see #makeIdempotent(String, Object, Supplier, Class )
74+ * @see #makeIdempotent(Function, Object, Class )
6675 */
6776public final class PowertoolsIdempotency {
6877
@@ -80,20 +89,22 @@ private PowertoolsIdempotency() {
8089 * such as batch processors.</p>
8190 *
8291 * <p>This method is suitable for making methods idempotent that have more than one parameter.
83- * For simple single-parameter methods, {@link #makeIdempotent(Function, Object)} is more intuitive.</p>
92+ * For simple single-parameter methods, {@link #makeIdempotent(Function, Object, Class )} is more intuitive.</p>
8493 *
8594 * <p><strong>Note:</strong> If you need to call different functions with the same payload,
86- * use {@link #makeIdempotent(String, Object, Supplier)} to specify distinct function names.
95+ * use {@link #makeIdempotent(String, Object, Supplier, Class )} to specify distinct function names.
8796 * This ensures each function has its own idempotency scope.</p>
8897 *
8998 * @param idempotencyKey the key used for idempotency (will be converted to JSON)
9099 * @param function the function to make idempotent
100+ * @param returnType the class of the return type for deserialization
91101 * @param <T> the return type of the function
92102 * @return the result of the function execution (either fresh or cached)
93103 * @throws Throwable if the function execution fails
94104 */
95- public static <T > T makeIdempotent (Object idempotencyKey , Supplier <T > function ) throws Throwable {
96- return makeIdempotent (DEFAULT_FUNCTION_NAME , idempotencyKey , function );
105+ public static <T > T makeIdempotent (Object idempotencyKey , Supplier <T > function , Class <T > returnType )
106+ throws Throwable {
107+ return makeIdempotent (DEFAULT_FUNCTION_NAME , idempotencyKey , function , returnType );
97108 }
98109
99110 /**
@@ -102,25 +113,24 @@ public static <T> T makeIdempotent(Object idempotencyKey, Supplier<T> function)
102113 * <p>This method is thread-safe and can be used in parallel processing scenarios
103114 * such as batch processors.</p>
104115 *
105- * <p>Note: The return type is inferred from the actual result. For cached responses,
106- * deserialization uses the runtime type of the stored result.</p>
107- *
108116 * @param functionName the name of the function (used for persistence store configuration)
109117 * @param idempotencyKey the key used for idempotency (will be converted to JSON)
110118 * @param function the function to make idempotent
119+ * @param returnType the class of the return type for deserialization
111120 * @param <T> the return type of the function
112121 * @return the result of the function execution (either fresh or cached)
113122 * @throws Throwable if the function execution fails
114123 */
115124 @ SuppressWarnings ("unchecked" )
116- public static <T > T makeIdempotent (String functionName , Object idempotencyKey , Supplier <T > function )
125+ public static <T > T makeIdempotent (String functionName , Object idempotencyKey , Supplier <T > function ,
126+ Class <T > returnType )
117127 throws Throwable {
118128 JsonNode payload = JsonConfig .get ().getObjectMapper ().valueToTree (idempotencyKey );
119129 Context lambdaContext = Idempotency .getInstance ().getConfig ().getLambdaContext ();
120130
121131 IdempotencyHandler handler = new IdempotencyHandler (
122132 function ::get ,
123- Object . class ,
133+ returnType ,
124134 functionName ,
125135 payload ,
126136 lambdaContext );
@@ -133,20 +143,21 @@ public static <T> T makeIdempotent(String functionName, Object idempotencyKey, S
133143 * Makes a function with one parameter idempotent.
134144 * The parameter is used as the idempotency key.
135145 *
136- * <p>For functions with more than one parameter, use {@link #makeIdempotent(Object, Supplier)} instead.</p>
146+ * <p>For functions with more than one parameter, use {@link #makeIdempotent(Object, Supplier, Class )} instead.</p>
137147 *
138148 * <p><strong>Note:</strong> If you need to call different functions with the same argument,
139- * use {@link #makeIdempotent(String, Object, Supplier)} to specify distinct function names.</p>
149+ * use {@link #makeIdempotent(String, Object, Supplier, Class )} to specify distinct function names.</p>
140150 *
141151 * @param function the function to make idempotent (method reference)
142152 * @param arg the argument to pass to the function (also used as idempotency key)
153+ * @param returnType the class of the return type for deserialization
143154 * @param <T> the argument type
144155 * @param <R> the return type
145156 * @return the result of the function execution (either fresh or cached)
146157 * @throws Throwable if the function execution fails
147158 */
148- public static <T , R > R makeIdempotent (Function <T , R > function , T arg ) throws Throwable {
149- return makeIdempotent (DEFAULT_FUNCTION_NAME , arg , () -> function .apply (arg ));
159+ public static <T , R > R makeIdempotent (Function <T , R > function , T arg , Class < R > returnType ) throws Throwable {
160+ return makeIdempotent (DEFAULT_FUNCTION_NAME , arg , () -> function .apply (arg ), returnType );
150161 }
151162
152163}
0 commit comments