This is an automated email from the ASF dual-hosted git repository.

oscerd pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new b4cc849ebad0 CAMEL-24329: camel-aws2-s3 - throw when pojoRequest=true 
and the body is the wrong type
b4cc849ebad0 is described below

commit b4cc849ebad04c261c7c3da317ff22c5296f0b37
Author: Andrea Cosentino <[email protected]>
AuthorDate: Mon Aug 3 16:50:43 2026 +0200

    CAMEL-24329: camel-aws2-s3 - throw when pojoRequest=true and the body is 
the wrong type
    
    Child of CAMEL-24261 (the final producer in the CAMEL-23462 completion 
sweep).
    
    AWS2S3Producer's 22 pojo-capable operations (object & bucket ops, tagging, 
ACLs,
    versioning, policies) only acted when the body was the matching request 
type under
    pojoRequest=true; any other body silently fell through with no AWS call and 
no
    error. Each branch now throws IllegalArgumentException naming the required 
request
    type, consistent with the CAMEL-23462 Bedrock fix. Covered by a Mockito
    parameterized unit test over all 22 operations. Main only, matching the 
CAMEL-23462
    precedent.
    
    Closes #25311
    
    Co-authored-by: Claude Opus 4.8 <[email protected]>
---
 components/camel-aws/camel-aws2-s3/pom.xml         | 11 +++
 .../camel/component/aws2/s3/AWS2S3Producer.java    | 66 +++++++++++++++++
 .../aws2/s3/AWS2S3ProducerPojoRequestTest.java     | 83 ++++++++++++++++++++++
 3 files changed, 160 insertions(+)

diff --git a/components/camel-aws/camel-aws2-s3/pom.xml 
b/components/camel-aws/camel-aws2-s3/pom.xml
index 947f6274f0b7..6cfecebaf776 100644
--- a/components/camel-aws/camel-aws2-s3/pom.xml
+++ b/components/camel-aws/camel-aws2-s3/pom.xml
@@ -88,5 +88,16 @@
             <version>${project.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-junit-jupiter</artifactId>
+            <version>${mockito-version}</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>
diff --git 
a/components/camel-aws/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/AWS2S3Producer.java
 
b/components/camel-aws/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/AWS2S3Producer.java
index b7ad0d2ca7a8..4b9bd26c7b5e 100644
--- 
a/components/camel-aws/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/AWS2S3Producer.java
+++ 
b/components/camel-aws/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/AWS2S3Producer.java
@@ -495,6 +495,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(result);
                 populateHttpResponseCode(result, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "copyObject operation requires CopyObjectRequest in 
POJO mode");
             }
         } else {
             if (ObjectHelper.isEmpty(bucketNameDestination)) {
@@ -576,6 +579,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(true);
                 populateHttpResponseCode(result, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "deleteObject operation requires DeleteObjectRequest 
in POJO mode");
             }
         } else {
             DeleteObjectRequest.Builder deleteObjectRequest = 
DeleteObjectRequest.builder().bucket(bucketName).key(keyName);
@@ -607,6 +613,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(resp);
                 populateHttpResponseCode(resp, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "deleteBucket operation requires DeleteBucketRequest 
in POJO mode");
             }
         } else {
             DeleteBucketRequest.Builder deleteBucketRequest = 
DeleteBucketRequest.builder().bucket(bucketName);
@@ -631,6 +640,9 @@ public class AWS2S3Producer extends DefaultProducer {
                     message.setBody(res);
                 }
                 populateMetadata(res, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "getObject operation requires GetObjectRequest in POJO 
mode");
             }
         } else {
             final String bucketName = 
AWS2S3Utils.determineBucketName(exchange, getConfiguration());
@@ -694,6 +706,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(res);
                 populateHttpResponseCode(res.response(), message);
+            } else {
+                throw new IllegalArgumentException(
+                        "getObjectRange operation requires GetObjectRequest in 
POJO mode");
             }
         } else {
             if (ObjectHelper.isEmpty(rangeStart) || 
ObjectHelper.isEmpty(rangeEnd)) {
@@ -734,6 +749,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(objectList.contents());
                 populateHttpResponseCode(objectList, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "listObjects operation requires ListObjectsV2Request 
in POJO mode");
             }
         } else {
             final String delimiter
@@ -846,6 +864,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(result);
                 populateHttpResponseCode(result, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "deleteObjects operation requires DeleteObjectsRequest 
in POJO mode");
             }
         } else {
             List<String> keysToDelete = 
exchange.getIn().getHeader(AWS2S3Constants.KEYS_TO_DELETE, List.class);
@@ -883,6 +904,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(result);
                 populateHttpResponseCode(result, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "restoreObject operation requires RestoreObjectRequest 
in POJO mode");
             }
         } else {
             Integer days = 
exchange.getIn().getHeader(AWS2S3Constants.RESTORE_DAYS, 1, Integer.class);
@@ -923,6 +947,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(result.tagSet());
                 populateHttpResponseCode(result, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "getObjectTagging operation requires 
GetObjectTaggingRequest in POJO mode");
             }
         } else {
             GetObjectTaggingRequest request = GetObjectTaggingRequest.builder()
@@ -951,6 +978,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(result);
                 populateHttpResponseCode(result, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "putObjectTagging operation requires 
PutObjectTaggingRequest in POJO mode");
             }
         } else {
             Map<String, String> tags = 
exchange.getIn().getHeader(AWS2S3Constants.OBJECT_TAGS, Map.class);
@@ -991,6 +1021,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(result);
                 populateHttpResponseCode(result, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "deleteObjectTagging operation requires 
DeleteObjectTaggingRequest in POJO mode");
             }
         } else {
             DeleteObjectTaggingRequest request = 
DeleteObjectTaggingRequest.builder()
@@ -1019,6 +1052,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(result);
                 populateHttpResponseCode(result, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "getObjectAcl operation requires GetObjectAclRequest 
in POJO mode");
             }
         } else {
             GetObjectAclRequest request = GetObjectAclRequest.builder()
@@ -1047,6 +1083,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(result);
                 populateHttpResponseCode(result, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "putObjectAcl operation requires PutObjectAclRequest 
in POJO mode");
             }
         } else {
             String cannedAcl = 
exchange.getIn().getHeader(AWS2S3Constants.CANNED_ACL, String.class);
@@ -1166,6 +1205,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(result);
                 populateHttpResponseCode(result, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "createBucket operation requires CreateBucketRequest 
in POJO mode");
             }
         } else {
             CreateBucketRequest.Builder requestBuilder = 
CreateBucketRequest.builder().bucket(bucketName);
@@ -1198,6 +1240,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(result.tagSet());
                 populateHttpResponseCode(result, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "getBucketTagging operation requires 
GetBucketTaggingRequest in POJO mode");
             }
         } else {
             GetBucketTaggingRequest request = GetBucketTaggingRequest.builder()
@@ -1223,6 +1268,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(result);
                 populateHttpResponseCode(result, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "putBucketTagging operation requires 
PutBucketTaggingRequest in POJO mode");
             }
         } else {
             Map<String, String> tags = 
exchange.getIn().getHeader(AWS2S3Constants.BUCKET_TAGS, Map.class);
@@ -1260,6 +1308,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(result);
                 populateHttpResponseCode(result, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "deleteBucketTagging operation requires 
DeleteBucketTaggingRequest in POJO mode");
             }
         } else {
             DeleteBucketTaggingRequest request = 
DeleteBucketTaggingRequest.builder()
@@ -1285,6 +1336,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(result);
                 populateHttpResponseCode(result, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "getBucketVersioning operation requires 
GetBucketVersioningRequest in POJO mode");
             }
         } else {
             GetBucketVersioningRequest request = 
GetBucketVersioningRequest.builder()
@@ -1310,6 +1364,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(result);
                 populateHttpResponseCode(result, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "putBucketVersioning operation requires 
PutBucketVersioningRequest in POJO mode");
             }
         } else {
             String versioningStatus = 
exchange.getIn().getHeader(AWS2S3Constants.VERSIONING_STATUS, String.class);
@@ -1349,6 +1406,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(result.policy());
                 populateHttpResponseCode(result, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "getBucketPolicy operation requires 
GetBucketPolicyRequest in POJO mode");
             }
         } else {
             GetBucketPolicyRequest request = GetBucketPolicyRequest.builder()
@@ -1374,6 +1434,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(result);
                 populateHttpResponseCode(result, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "putBucketPolicy operation requires 
PutBucketPolicyRequest in POJO mode");
             }
         } else {
             String policy = 
exchange.getIn().getHeader(AWS2S3Constants.BUCKET_POLICY, String.class);
@@ -1405,6 +1468,9 @@ public class AWS2S3Producer extends DefaultProducer {
                 Message message = getMessageForResponse(exchange);
                 message.setBody(result);
                 populateHttpResponseCode(result, message);
+            } else {
+                throw new IllegalArgumentException(
+                        "deleteBucketPolicy operation requires 
DeleteBucketPolicyRequest in POJO mode");
             }
         } else {
             DeleteBucketPolicyRequest request = 
DeleteBucketPolicyRequest.builder()
diff --git 
a/components/camel-aws/camel-aws2-s3/src/test/java/org/apache/camel/component/aws2/s3/AWS2S3ProducerPojoRequestTest.java
 
b/components/camel-aws/camel-aws2-s3/src/test/java/org/apache/camel/component/aws2/s3/AWS2S3ProducerPojoRequestTest.java
new file mode 100644
index 000000000000..b91c62eb49b6
--- /dev/null
+++ 
b/components/camel-aws/camel-aws2-s3/src/test/java/org/apache/camel/component/aws2/s3/AWS2S3ProducerPojoRequestTest.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 org.apache.camel.component.aws2.s3;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.support.DefaultExchange;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import software.amazon.awssdk.services.s3.S3Client;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * When {@code pojoRequest=true}, the producer must fail fast if the body is 
not the expected request type, rather than
+ * silently doing nothing (see CAMEL-24261).
+ */
+class AWS2S3ProducerPojoRequestTest {
+
+    @ParameterizedTest
+    @CsvSource({
+            "copyObject,copyObject operation requires CopyObjectRequest in 
POJO mode",
+            "deleteObject,deleteObject operation requires DeleteObjectRequest 
in POJO mode",
+            "deleteBucket,deleteBucket operation requires DeleteBucketRequest 
in POJO mode",
+            "getObject,getObject operation requires GetObjectRequest in POJO 
mode",
+            "getObjectRange,getObjectRange operation requires GetObjectRequest 
in POJO mode",
+            "listObjects,listObjects operation requires ListObjectsV2Request 
in POJO mode",
+            "deleteObjects,deleteObjects operation requires 
DeleteObjectsRequest in POJO mode",
+            "restoreObject,restoreObject operation requires 
RestoreObjectRequest in POJO mode",
+            "getObjectTagging,getObjectTagging operation requires 
GetObjectTaggingRequest in POJO mode",
+            "putObjectTagging,putObjectTagging operation requires 
PutObjectTaggingRequest in POJO mode",
+            "deleteObjectTagging,deleteObjectTagging operation requires 
DeleteObjectTaggingRequest in POJO mode",
+            "getObjectAcl,getObjectAcl operation requires GetObjectAclRequest 
in POJO mode",
+            "putObjectAcl,putObjectAcl operation requires PutObjectAclRequest 
in POJO mode",
+            "createBucket,createBucket operation requires CreateBucketRequest 
in POJO mode",
+            "getBucketTagging,getBucketTagging operation requires 
GetBucketTaggingRequest in POJO mode",
+            "putBucketTagging,putBucketTagging operation requires 
PutBucketTaggingRequest in POJO mode",
+            "deleteBucketTagging,deleteBucketTagging operation requires 
DeleteBucketTaggingRequest in POJO mode",
+            "getBucketVersioning,getBucketVersioning operation requires 
GetBucketVersioningRequest in POJO mode",
+            "putBucketVersioning,putBucketVersioning operation requires 
PutBucketVersioningRequest in POJO mode",
+            "getBucketPolicy,getBucketPolicy operation requires 
GetBucketPolicyRequest in POJO mode",
+            "putBucketPolicy,putBucketPolicy operation requires 
PutBucketPolicyRequest in POJO mode",
+            "deleteBucketPolicy,deleteBucketPolicy operation requires 
DeleteBucketPolicyRequest in POJO mode",
+    })
+    void pojoRequestWithWrongBodyTypeThrows(String operation, String 
expectedMessage) throws Exception {
+        AWS2S3Configuration configuration = new AWS2S3Configuration();
+        configuration.setPojoRequest(true);
+        configuration.setOperation(AWS2S3Operations.valueOf(operation));
+        // some operations resolve the bucket/key before the pojo-type check; 
supply them so the wrong-typed
+        // body reaches the instanceof guard we are exercising
+        configuration.setBucketName("test-bucket");
+        configuration.setKeyName("test-key");
+
+        AWS2S3Endpoint endpoint = mock(AWS2S3Endpoint.class);
+        when(endpoint.getConfiguration()).thenReturn(configuration);
+        when(endpoint.getS3Client()).thenReturn(mock(S3Client.class));
+
+        AWS2S3Producer producer = new AWS2S3Producer(endpoint);
+
+        Exchange exchange = new DefaultExchange(new DefaultCamelContext());
+        exchange.getIn().setBody("not the expected request type");
+
+        assertThatThrownBy(() -> producer.process(exchange))
+                .isInstanceOf(IllegalArgumentException.class)
+                .hasMessage(expectedMessage);
+    }
+}

Reply via email to