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);
+ }
+}