You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by je...@apache.org on 2021/03/24 17:40:33 UTC

[camel] branch master updated: CAMEL-16368: Add support for salesforce Composite SObject Collections API (#5259)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 701fa4a  CAMEL-16368: Add support for salesforce Composite SObject Collections API (#5259)
701fa4a is described below

commit 701fa4a301bb84287adbcf96b5b95e21d0c36f29
Author: Jeremy Ross <je...@gmail.com>
AuthorDate: Wed Mar 24 12:40:11 2021 -0500

    CAMEL-16368: Add support for salesforce Composite SObject Collections API (#5259)
---
 .../camel/catalog/docs/salesforce-component.adoc   |  77 ++++++-
 .../salesforce/SalesforceComponentConfigurer.java  |   6 +
 .../salesforce/SalesforceEndpointConfigurer.java   |   6 +
 .../salesforce/SalesforceEndpointUriFactory.java   |   3 +-
 .../camel/component/salesforce/salesforce.json     |   4 +-
 .../src/main/docs/salesforce-component.adoc        |  77 ++++++-
 .../component/salesforce/SalesforceEndpoint.java   |   3 +
 .../salesforce/SalesforceEndpointConfig.java       |  13 ++
 .../component/salesforce/SalesforceProducer.java   |  20 +-
 .../salesforce/api/dto/DeleteSObjectResult.java    |  55 +++++
 .../salesforce/api/dto/SaveSObjectResult.java      |  55 +++++
 .../api/dto/composite/SObjectCollection.java       |  49 +++++
 .../salesforce/internal/OperationName.java         |  11 +-
 .../internal/client/AbstractClientBase.java        |   7 +-
 .../CompositeSObjectCollectionsApiClient.java      |  51 +++++
 .../internal/client/DefaultCompositeApiClient.java |  11 +-
 ...efaultCompositeSObjectCollectionsApiClient.java | 232 +++++++++++++++++++++
 .../composite/RetrieveSObjectCollectionsDto.java   |  39 ++++
 .../internal/processor/AbstractRestProcessor.java  |  26 +--
 .../processor/AbstractSalesforceProcessor.java     |  40 ++++
 .../CompositeSObjectCollectionsProcessor.java      | 202 ++++++++++++++++++
 .../CompositeApiCollectionsIntegrationTest.java    | 195 +++++++++++++++++
 .../dsl/SalesforceComponentBuilderFactory.java     |  17 ++
 .../builder/endpoint/StaticEndpointBuilders.java   |  34 +--
 .../dsl/SalesforceEndpointBuilderFactory.java      |  55 ++++-
 .../modules/ROOT/pages/salesforce-component.adoc   |  77 ++++++-
 26 files changed, 1279 insertions(+), 86 deletions(-)

diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/salesforce-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/salesforce-component.adoc
index 4d5bef8..20a23dd 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/salesforce-component.adoc
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/salesforce-component.adoc
@@ -158,7 +158,14 @@ results) using result link returned from the 'query' API
 * composite - submit up to 25 possibly related REST requests and receive individual responses. It's also possible to use "raw" composite without limitation.
 * composite-tree - create up to 200 records with parent-child relationships (up to 5 levels) in one go
 * composite-batch - submit a composition of requests in batch
-* queryAll - Runs a SOQL query. It returns the results that are deleted because of a merge or delete. Also returns the  information about archived Task and Event records.
+* compositeRetrieveSObjectCollections - Retrieve one or more records of the same object type.
+* compositeCreateSObjectCollections - Add up to 200 records, returning a list of SaveSObjectResult objects.
+* compositeUpdateSObjectCollections - Update up to 200 records, returning a list of SaveSObjectResult objects.
+* compositeUpsertSObjectCollections - Create or update (upsert) up to 200 records based on an external ID field.
+Returns a list of UpsertSObjectResult objects.
+* compositeDeleteSObjectCollections - Delete up to 200 records, returning a list of SaveSObjectResult objects.
+* queryAll - Runs a SOQL query. It returns the results that are deleted because of a merge or delete. Also returns
+the  information about archived Task and Event records.
 * getBlobField - Retrieves the specified blob field from an individual record.
 * apexCall - Executes a user defined APEX REST API call.
 
@@ -667,6 +674,60 @@ With this approach, you have the complete control on the Salesforce request.
 `compositeMethod` option to override to the other supported value, `GET`, which returns a list of
 other available composite resources.
 
+== Using Composite SObject Collections
+
+The SObject Collections API executes actions on multiple records in one request. Use sObject Collections to reduce the number of round-trips between the client and server. The entire request counts as a single call toward your API limits. This resource is available in API version 42.0 and later. `SObject` records (aka DTOs) supplied to these operations must be instances of subclasses of `AbstractDescribedSObjectBase`. See the Maven Plugin section for information on generating these DTO c [...]
+
+=== compositeRetrieveSObjectCollections
+Retrieve one or more records of the same object type.
+|===
+| Parameter | Type | Description | Default | Required
+
+| ids | List of String or comma-separated string | A list of one or more IDs of the objects to return. All IDs must belong to the same object type. | | x
+| fields | List of String or comma-separated string | A list of fields to include in the response. The field names you specify must be valid, and you must have read-level permissions to each field. | | x
+| sObjectName | String | Type of SObject, e.g. `Account` | | x
+| sObjectClass | String | Fully-qualified class name of DTO class to use for deserializing the response. | | Required if `sObjectName` parameter does not resolve to a class that exists in the package specified by the `package` option.
+|===
+
+=== compositeCreateSObjectCollections
+Add up to 200 records, returning a list of SaveSObjectResult objects. Mixed SObject types is supported.
+|===
+| Parameter | Type | Description| Default| Required
+
+| request body | List of `SObject` | A list of SObjects to create | | x
+| allOrNone | boolean | Indicates whether to roll back the entire request when the creation of any object fails (true) or to continue with the independent creation of other objects in the request. | false |
+|===
+
+=== compositeUpdateSObjectCollections
+Update up to 200 records, returning a list of SaveSObjectResult objects. Mixed SObject types is supported.
+|===
+| Parameter | Type | Description | Default | Required
+
+| request body | List of `SObject` | A list of SObjects to update | | x
+| allOrNone | boolean | Indicates whether to roll back the entire request when the update of any object fails (true) or to continue with the independent update of other objects in the request. | false |
+|===
+
+=== compositeUpsertSObjectCollections
+Create or update (upsert) up to 200 records based on an external ID field, returning a list of UpsertSObjectResult
+objects. Mixed SObject types is not supported.
+|===
+| Parameter | Type | Description | Default | Required
+
+| request body | List of `SObject` | A list of SObjects to upsert | | x
+| allOrNone | boolean |  Indicates whether to roll back the entire request when the upsert of any object fails (true) or to continue with the independent upsert of other objects in the request. | false |
+| sObjectName | String | Type of SObject, e.g. `Account` | | x
+| sObjectIdName | String | Name of External ID field | | x
+|===
+
+=== compositeDeleteSObjectCollections
+Delete up to 200 records, returning a list of DeleteSObjectResult objects. Mixed SObject types is supported.
+|===
+| Parameter | Type | Description | Default | Required
+
+| ids | List of String or comma-separated string | A list of up to 200 IDs of objects to be deleted. | | x
+| allOrNone | boolean | Indicates whether to roll back the entire request when the upsert of any object fails (true) or to continue with the independent upsert of other objects in the request. | false |
+|===
+
 
 ==  Sending null values to salesforce
 
@@ -715,14 +776,8 @@ for details on how to generate the DTO.
 
 == Options
 
-
-
-
-
-
-
 // component options: START
-The Salesforce component supports 79 options, which are listed below.
+The Salesforce component supports 80 options, which are listed below.
 
 
 
@@ -780,6 +835,7 @@ The Salesforce component supports 79 options, which are listed below.
 | *httpClientProperties* (common) | Used to set any properties that can be configured on the underlying HTTP client. Have a look at properties of SalesforceHttpClient and the Jetty HttpClient for all available options. |  | Map
 | *longPollingTransportProperties* (common) | Used to set any properties that can be configured on the LongPollingTransport used by the BayeuxClient (CometD) used by the streaming api |  | Map
 | *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
+| *allOrNone* (producer) | Composite API option to indicate to rollback all records if any are not successful. | false | boolean
 | *apexUrl* (producer) | APEX method URL |  | String
 | *compositeMethod* (producer) | Composite (raw) method. |  | String
 | *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...]
@@ -835,12 +891,12 @@ with the following path and query parameters:
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
 | Name | Description | Default | Type
-| *operationName* | The operation to use. There are 59 enums and the value can be one of: getVersions, getResources, getGlobalObjects, getBasicInfo, getDescription, getSObject, createSObject, updateSObject, deleteSObject, getSObjectWithId, upsertSObject, deleteSObjectWithId, getBlobField, query, queryMore, queryAll, search, apexCall, recent, createJob, getJob, closeJob, abortJob, createBatch, getBatch, getAllBatches, getRequest, getResults, createBatchQuery, getQueryResultIds, getQueryRe [...]
+| *operationName* | The operation to use. There are 64 enums and the value can be one of: getVersions, getResources, getGlobalObjects, getBasicInfo, getDescription, getSObject, createSObject, updateSObject, deleteSObject, getSObjectWithId, upsertSObject, deleteSObjectWithId, getBlobField, query, queryMore, queryAll, search, apexCall, recent, createJob, getJob, closeJob, abortJob, createBatch, getBatch, getAllBatches, getRequest, getResults, createBatchQuery, getQueryResultIds, getQueryRe [...]
 | *topicName* | The name of the topic/channel to use |  | String
 |===
 
 
-=== Query Parameters (49 parameters):
+=== Query Parameters (50 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -892,6 +948,7 @@ with the following path and query parameters:
 | *replayId* (consumer) | The replayId value to use when subscribing |  | Long
 | *exceptionHandler* (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
 | *exchangePattern* (consumer) | Sets the exchange pattern when the consumer creates an exchange. There are 3 enums and the value can be one of: InOnly, InOut, InOptionalOut |  | ExchangePattern
+| *allOrNone* (producer) | Composite API option to indicate to rollback all records if any are not successful. | false | boolean
 | *apexUrl* (producer) | APEX method URL |  | String
 | *compositeMethod* (producer) | Composite (raw) method. |  | String
 | *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...]
diff --git a/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceComponentConfigurer.java b/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceComponentConfigurer.java
index 24f0acad..f6197e8 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceComponentConfigurer.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceComponentConfigurer.java
@@ -28,6 +28,8 @@ public class SalesforceComponentConfigurer extends PropertyConfigurerSupport imp
     public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
         SalesforceComponent target = (SalesforceComponent) obj;
         switch (ignoreCase ? name.toLowerCase() : name) {
+        case "allornone":
+        case "allOrNone": getOrCreateConfig(target).setAllOrNone(property(camelContext, boolean.class, value)); return true;
         case "apexmethod":
         case "apexMethod": getOrCreateConfig(target).setApexMethod(property(camelContext, java.lang.String.class, value)); return true;
         case "apexqueryparams":
@@ -187,6 +189,8 @@ public class SalesforceComponentConfigurer extends PropertyConfigurerSupport imp
     @Override
     public Class<?> getOptionType(String name, boolean ignoreCase) {
         switch (ignoreCase ? name.toLowerCase() : name) {
+        case "allornone":
+        case "allOrNone": return boolean.class;
         case "apexmethod":
         case "apexMethod": return java.lang.String.class;
         case "apexqueryparams":
@@ -347,6 +351,8 @@ public class SalesforceComponentConfigurer extends PropertyConfigurerSupport imp
     public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
         SalesforceComponent target = (SalesforceComponent) obj;
         switch (ignoreCase ? name.toLowerCase() : name) {
+        case "allornone":
+        case "allOrNone": return getOrCreateConfig(target).isAllOrNone();
         case "apexmethod":
         case "apexMethod": return getOrCreateConfig(target).getApexMethod();
         case "apexqueryparams":
diff --git a/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceEndpointConfigurer.java b/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceEndpointConfigurer.java
index 9615232..23abe0a 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceEndpointConfigurer.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceEndpointConfigurer.java
@@ -21,6 +21,8 @@ public class SalesforceEndpointConfigurer extends PropertyConfigurerSupport impl
     public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
         SalesforceEndpoint target = (SalesforceEndpoint) obj;
         switch (ignoreCase ? name.toLowerCase() : name) {
+        case "allornone":
+        case "allOrNone": target.getConfiguration().setAllOrNone(property(camelContext, boolean.class, value)); return true;
         case "apexmethod":
         case "apexMethod": target.getConfiguration().setApexMethod(property(camelContext, java.lang.String.class, value)); return true;
         case "apexqueryparams":
@@ -124,6 +126,8 @@ public class SalesforceEndpointConfigurer extends PropertyConfigurerSupport impl
     @Override
     public Class<?> getOptionType(String name, boolean ignoreCase) {
         switch (ignoreCase ? name.toLowerCase() : name) {
+        case "allornone":
+        case "allOrNone": return boolean.class;
         case "apexmethod":
         case "apexMethod": return java.lang.String.class;
         case "apexqueryparams":
@@ -228,6 +232,8 @@ public class SalesforceEndpointConfigurer extends PropertyConfigurerSupport impl
     public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
         SalesforceEndpoint target = (SalesforceEndpoint) obj;
         switch (ignoreCase ? name.toLowerCase() : name) {
+        case "allornone":
+        case "allOrNone": return target.getConfiguration().isAllOrNone();
         case "apexmethod":
         case "apexMethod": return target.getConfiguration().getApexMethod();
         case "apexqueryparams":
diff --git a/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceEndpointUriFactory.java b/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceEndpointUriFactory.java
index ea133d3..c92251d 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceEndpointUriFactory.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/generated/java/org/apache/camel/component/salesforce/SalesforceEndpointUriFactory.java
@@ -20,7 +20,7 @@ public class SalesforceEndpointUriFactory extends org.apache.camel.support.compo
     private static final Set<String> PROPERTY_NAMES;
     private static final Set<String> SECRET_PROPERTY_NAMES;
     static {
-        Set<String> props = new HashSet<>(51);
+        Set<String> props = new HashSet<>(52);
         props.add("initialReplayIdMap");
         props.add("notifyForOperations");
         props.add("sObjectQuery");
@@ -70,6 +70,7 @@ public class SalesforceEndpointUriFactory extends org.apache.camel.support.compo
         props.add("operationName");
         props.add("pkChunking");
         props.add("notFoundBehaviour");
+        props.add("allOrNone");
         props.add("topicName");
         props.add("notifyForOperationDelete");
         PROPERTY_NAMES = Collections.unmodifiableSet(props);
diff --git a/components/camel-salesforce/camel-salesforce-component/src/generated/resources/org/apache/camel/component/salesforce/salesforce.json b/components/camel-salesforce/camel-salesforce-component/src/generated/resources/org/apache/camel/component/salesforce/salesforce.json
index f4d967e..dfc2bcf 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/generated/resources/org/apache/camel/component/salesforce/salesforce.json
+++ b/components/camel-salesforce/camel-salesforce-component/src/generated/resources/org/apache/camel/component/salesforce/salesforce.json
@@ -74,6 +74,7 @@
     "httpClientProperties": { "kind": "property", "displayName": "Http Client Properties", "group": "common (advanced)", "label": "common,advanced", "required": false, "type": "object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>", "deprecated": false, "autowired": false, "secret": false, "description": "Used to set any properties that can be configured on the underlying HTTP client. Have a look at properties of SalesforceHttpClient and the Jetty HttpClient for all ava [...]
     "longPollingTransportProperties": { "kind": "property", "displayName": "Long Polling Transport Properties", "group": "common (advanced)", "label": "common,advanced", "required": false, "type": "object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>", "deprecated": false, "autowired": false, "secret": false, "description": "Used to set any properties that can be configured on the LongPollingTransport used by the BayeuxClient (CometD) used by the streaming api" },
     "bridgeErrorHandler": { "kind": "property", "displayName": "Bridge Error Handler", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a me [...]
+    "allOrNone": { "kind": "property", "displayName": "All Or None", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.salesforce.SalesforceEndpointConfig", "configurationField": "config", "description": "Composite API option to indicate to rollback all records if any are not successful." },
     "apexUrl": { "kind": "property", "displayName": "Apex Url", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.salesforce.SalesforceEndpointConfig", "configurationField": "config", "description": "APEX method URL" },
     "compositeMethod": { "kind": "property", "displayName": "Composite Method", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.salesforce.SalesforceEndpointConfig", "configurationField": "config", "description": "Composite (raw) method." },
     "lazyStartProducer": { "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during star [...]
@@ -104,7 +105,7 @@
     "userName": { "kind": "property", "displayName": "User Name", "group": "security", "label": "common,security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Username used in OAuth flow to gain access to access token. It's easy to get started with password OAuth flow, but in general one should avoid it as it is deemed less secure than other flows." }
   },
   "properties": {
-    "operationName": { "kind": "path", "displayName": "Operation Name", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.component.salesforce.internal.OperationName", "enum": [ "getVersions", "getResources", "getGlobalObjects", "getBasicInfo", "getDescription", "getSObject", "createSObject", "updateSObject", "deleteSObject", "getSObjectWithId", "upsertSObject", "deleteSObjectWithId", "getBlobField", "query", "queryMore", "queryA [...]
+    "operationName": { "kind": "path", "displayName": "Operation Name", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.component.salesforce.internal.OperationName", "enum": [ "getVersions", "getResources", "getGlobalObjects", "getBasicInfo", "getDescription", "getSObject", "createSObject", "updateSObject", "deleteSObject", "getSObjectWithId", "upsertSObject", "deleteSObjectWithId", "getBlobField", "query", "queryMore", "queryA [...]
     "topicName": { "kind": "path", "displayName": "Topic Name", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The name of the topic\/channel to use" },
     "apexMethod": { "kind": "parameter", "displayName": "Apex Method", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.salesforce.SalesforceEndpointConfig", "configurationField": "configuration", "description": "APEX method name" },
     "apexQueryParams": { "kind": "parameter", "displayName": "Apex Query Params", "group": "common", "label": "", "required": false, "type": "object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.salesforce.SalesforceEndpointConfig", "configurationField": "configuration", "description": "Query params for APEX method" },
@@ -152,6 +153,7 @@
     "replayId": { "kind": "parameter", "displayName": "Replay Id", "group": "consumer", "label": "consumer", "required": false, "type": "integer", "javaType": "java.lang.Long", "deprecated": false, "autowired": false, "secret": false, "description": "The replayId value to use when subscribing" },
     "exceptionHandler": { "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "autowired": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the con [...]
     "exchangePattern": { "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut", "InOptionalOut" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." },
+    "allOrNone": { "kind": "parameter", "displayName": "All Or None", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.salesforce.SalesforceEndpointConfig", "configurationField": "configuration", "description": "Composite API option to indicate to rollback all records if any are not successful." },
     "apexUrl": { "kind": "parameter", "displayName": "Apex Url", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.salesforce.SalesforceEndpointConfig", "configurationField": "configuration", "description": "APEX method URL" },
     "compositeMethod": { "kind": "parameter", "displayName": "Composite Method", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.salesforce.SalesforceEndpointConfig", "configurationField": "configuration", "description": "Composite (raw) method." },
     "lazyStartProducer": { "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during sta [...]
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/docs/salesforce-component.adoc b/components/camel-salesforce/camel-salesforce-component/src/main/docs/salesforce-component.adoc
index 4d5bef8..20a23dd 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/docs/salesforce-component.adoc
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/docs/salesforce-component.adoc
@@ -158,7 +158,14 @@ results) using result link returned from the 'query' API
 * composite - submit up to 25 possibly related REST requests and receive individual responses. It's also possible to use "raw" composite without limitation.
 * composite-tree - create up to 200 records with parent-child relationships (up to 5 levels) in one go
 * composite-batch - submit a composition of requests in batch
-* queryAll - Runs a SOQL query. It returns the results that are deleted because of a merge or delete. Also returns the  information about archived Task and Event records.
+* compositeRetrieveSObjectCollections - Retrieve one or more records of the same object type.
+* compositeCreateSObjectCollections - Add up to 200 records, returning a list of SaveSObjectResult objects.
+* compositeUpdateSObjectCollections - Update up to 200 records, returning a list of SaveSObjectResult objects.
+* compositeUpsertSObjectCollections - Create or update (upsert) up to 200 records based on an external ID field.
+Returns a list of UpsertSObjectResult objects.
+* compositeDeleteSObjectCollections - Delete up to 200 records, returning a list of SaveSObjectResult objects.
+* queryAll - Runs a SOQL query. It returns the results that are deleted because of a merge or delete. Also returns
+the  information about archived Task and Event records.
 * getBlobField - Retrieves the specified blob field from an individual record.
 * apexCall - Executes a user defined APEX REST API call.
 
@@ -667,6 +674,60 @@ With this approach, you have the complete control on the Salesforce request.
 `compositeMethod` option to override to the other supported value, `GET`, which returns a list of
 other available composite resources.
 
+== Using Composite SObject Collections
+
+The SObject Collections API executes actions on multiple records in one request. Use sObject Collections to reduce the number of round-trips between the client and server. The entire request counts as a single call toward your API limits. This resource is available in API version 42.0 and later. `SObject` records (aka DTOs) supplied to these operations must be instances of subclasses of `AbstractDescribedSObjectBase`. See the Maven Plugin section for information on generating these DTO c [...]
+
+=== compositeRetrieveSObjectCollections
+Retrieve one or more records of the same object type.
+|===
+| Parameter | Type | Description | Default | Required
+
+| ids | List of String or comma-separated string | A list of one or more IDs of the objects to return. All IDs must belong to the same object type. | | x
+| fields | List of String or comma-separated string | A list of fields to include in the response. The field names you specify must be valid, and you must have read-level permissions to each field. | | x
+| sObjectName | String | Type of SObject, e.g. `Account` | | x
+| sObjectClass | String | Fully-qualified class name of DTO class to use for deserializing the response. | | Required if `sObjectName` parameter does not resolve to a class that exists in the package specified by the `package` option.
+|===
+
+=== compositeCreateSObjectCollections
+Add up to 200 records, returning a list of SaveSObjectResult objects. Mixed SObject types is supported.
+|===
+| Parameter | Type | Description| Default| Required
+
+| request body | List of `SObject` | A list of SObjects to create | | x
+| allOrNone | boolean | Indicates whether to roll back the entire request when the creation of any object fails (true) or to continue with the independent creation of other objects in the request. | false |
+|===
+
+=== compositeUpdateSObjectCollections
+Update up to 200 records, returning a list of SaveSObjectResult objects. Mixed SObject types is supported.
+|===
+| Parameter | Type | Description | Default | Required
+
+| request body | List of `SObject` | A list of SObjects to update | | x
+| allOrNone | boolean | Indicates whether to roll back the entire request when the update of any object fails (true) or to continue with the independent update of other objects in the request. | false |
+|===
+
+=== compositeUpsertSObjectCollections
+Create or update (upsert) up to 200 records based on an external ID field, returning a list of UpsertSObjectResult
+objects. Mixed SObject types is not supported.
+|===
+| Parameter | Type | Description | Default | Required
+
+| request body | List of `SObject` | A list of SObjects to upsert | | x
+| allOrNone | boolean |  Indicates whether to roll back the entire request when the upsert of any object fails (true) or to continue with the independent upsert of other objects in the request. | false |
+| sObjectName | String | Type of SObject, e.g. `Account` | | x
+| sObjectIdName | String | Name of External ID field | | x
+|===
+
+=== compositeDeleteSObjectCollections
+Delete up to 200 records, returning a list of DeleteSObjectResult objects. Mixed SObject types is supported.
+|===
+| Parameter | Type | Description | Default | Required
+
+| ids | List of String or comma-separated string | A list of up to 200 IDs of objects to be deleted. | | x
+| allOrNone | boolean | Indicates whether to roll back the entire request when the upsert of any object fails (true) or to continue with the independent upsert of other objects in the request. | false |
+|===
+
 
 ==  Sending null values to salesforce
 
@@ -715,14 +776,8 @@ for details on how to generate the DTO.
 
 == Options
 
-
-
-
-
-
-
 // component options: START
-The Salesforce component supports 79 options, which are listed below.
+The Salesforce component supports 80 options, which are listed below.
 
 
 
@@ -780,6 +835,7 @@ The Salesforce component supports 79 options, which are listed below.
 | *httpClientProperties* (common) | Used to set any properties that can be configured on the underlying HTTP client. Have a look at properties of SalesforceHttpClient and the Jetty HttpClient for all available options. |  | Map
 | *longPollingTransportProperties* (common) | Used to set any properties that can be configured on the LongPollingTransport used by the BayeuxClient (CometD) used by the streaming api |  | Map
 | *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
+| *allOrNone* (producer) | Composite API option to indicate to rollback all records if any are not successful. | false | boolean
 | *apexUrl* (producer) | APEX method URL |  | String
 | *compositeMethod* (producer) | Composite (raw) method. |  | String
 | *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...]
@@ -835,12 +891,12 @@ with the following path and query parameters:
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
 | Name | Description | Default | Type
-| *operationName* | The operation to use. There are 59 enums and the value can be one of: getVersions, getResources, getGlobalObjects, getBasicInfo, getDescription, getSObject, createSObject, updateSObject, deleteSObject, getSObjectWithId, upsertSObject, deleteSObjectWithId, getBlobField, query, queryMore, queryAll, search, apexCall, recent, createJob, getJob, closeJob, abortJob, createBatch, getBatch, getAllBatches, getRequest, getResults, createBatchQuery, getQueryResultIds, getQueryRe [...]
+| *operationName* | The operation to use. There are 64 enums and the value can be one of: getVersions, getResources, getGlobalObjects, getBasicInfo, getDescription, getSObject, createSObject, updateSObject, deleteSObject, getSObjectWithId, upsertSObject, deleteSObjectWithId, getBlobField, query, queryMore, queryAll, search, apexCall, recent, createJob, getJob, closeJob, abortJob, createBatch, getBatch, getAllBatches, getRequest, getResults, createBatchQuery, getQueryResultIds, getQueryRe [...]
 | *topicName* | The name of the topic/channel to use |  | String
 |===
 
 
-=== Query Parameters (49 parameters):
+=== Query Parameters (50 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -892,6 +948,7 @@ with the following path and query parameters:
 | *replayId* (consumer) | The replayId value to use when subscribing |  | Long
 | *exceptionHandler* (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
 | *exchangePattern* (consumer) | Sets the exchange pattern when the consumer creates an exchange. There are 3 enums and the value can be one of: InOnly, InOut, InOptionalOut |  | ExchangePattern
+| *allOrNone* (producer) | Composite API option to indicate to rollback all records if any are not successful. | false | boolean
 | *apexUrl* (producer) | APEX method URL |  | String
 | *compositeMethod* (producer) | Composite (raw) method. |  | String
 | *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...]
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpoint.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpoint.java
index e48b610..7070af0 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpoint.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpoint.java
@@ -48,6 +48,9 @@ public class SalesforceEndpoint extends DefaultEndpoint {
             + "createBatchQuery,getQueryResultIds,getQueryResult,getRecentReports,"
             + "getReportDescription,executeSyncReport,executeAsyncReport,getReportInstances,"
             + "getReportResults,limits,approval,approvals,composite-tree,composite-batch,composite,"
+            + "compositeRetrieveSObjectCollections,compositeCreateSObjectCollections,"
+            + "compositeUpdateSObjectCollections,compositeUpsertSObjectCollections,"
+            + "compositeDeleteSObjectCollections,"
             + "bulk2GetAllJobs,bulk2CreateJob,bulk2GetJob,bulk2CreateBatch,bulk2CloseJob,"
             + "bulk2AbortJob,bulk2DeleteJob,bulk2GetSuccessfulResults,bulk2GetFailedResults,"
             + "bulk2GetUnprocessedRecords,bulk2CreateQueryJob,bulk2GetQueryJob,"
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpointConfig.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpointConfig.java
index 0c9801b..6d3d2eb 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpointConfig.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceEndpointConfig.java
@@ -52,6 +52,7 @@ public class SalesforceEndpointConfig implements Cloneable {
 
     public static final String SOBJECT_NAME = "sObjectName";
     public static final String SOBJECT_ID = "sObjectId";
+    public static final String SOBJECT_IDS = "sObjectIds";
     public static final String SOBJECT_FIELDS = "sObjectFields";
     public static final String SOBJECT_EXT_ID_NAME = "sObjectIdName";
     public static final String SOBJECT_EXT_ID_VALUE = "sObjectIdValue";
@@ -63,6 +64,7 @@ public class SalesforceEndpointConfig implements Cloneable {
     public static final String APEX_URL = "apexUrl";
     public static final String COMPOSITE_METHOD = "compositeMethod";
     public static final String LIMIT = "limit";
+    public static final String ALL_OR_NONE = "allOrNone";
 
     // prefix for parameters in headers
     public static final String APEX_QUERY_PARAM_PREFIX = "apexQueryParam.";
@@ -133,6 +135,9 @@ public class SalesforceEndpointConfig implements Cloneable {
     private String apexMethod;
     @UriParam(label = "producer")
     private String compositeMethod;
+    @UriParam(label = "producer", defaultValue = "false", description = "Composite API option to indicate" +
+                                                                        " to rollback all records if any are not successful.")
+    private boolean allOrNone = false;
     @UriParam(label = "producer")
     private String apexUrl;
     @UriParam
@@ -406,6 +411,14 @@ public class SalesforceEndpointConfig implements Cloneable {
         this.compositeMethod = compositeMethod;
     }
 
+    public boolean isAllOrNone() {
+        return allOrNone;
+    }
+
+    public void setAllOrNone(boolean allOrNone) {
+        this.allOrNone = allOrNone;
+    }
+
     public ApprovalRequest getApproval() {
         return approval;
     }
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceProducer.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceProducer.java
index 5d5f0e0..4569bfd 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceProducer.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceProducer.java
@@ -27,6 +27,7 @@ import org.apache.camel.component.salesforce.internal.processor.AnalyticsApiProc
 import org.apache.camel.component.salesforce.internal.processor.BulkApiProcessor;
 import org.apache.camel.component.salesforce.internal.processor.BulkApiV2Processor;
 import org.apache.camel.component.salesforce.internal.processor.CompositeApiProcessor;
+import org.apache.camel.component.salesforce.internal.processor.CompositeSObjectCollectionsProcessor;
 import org.apache.camel.component.salesforce.internal.processor.JsonRestProcessor;
 import org.apache.camel.component.salesforce.internal.processor.SalesforceProcessor;
 import org.apache.camel.component.salesforce.internal.processor.XmlRestProcessor;
@@ -60,6 +61,8 @@ public class SalesforceProducer extends DefaultAsyncProducer {
             processor = new AnalyticsApiProcessor(endpoint);
         } else if (isCompositeOperation(operationName)) {
             processor = new CompositeApiProcessor(endpoint);
+        } else if (isCompositeSObjectCollectionsOperation(operationName)) {
+            processor = new CompositeSObjectCollectionsProcessor(endpoint);
         } else {
             // create an appropriate processor
             if (payloadFormat == PayloadFormat.JSON) {
@@ -131,9 +134,22 @@ public class SalesforceProducer extends DefaultAsyncProducer {
 
     private static boolean isCompositeOperation(OperationName operationName) {
         switch (operationName) {
-            case COMPOSITE_TREE:
-            case COMPOSITE_BATCH:
             case COMPOSITE:
+            case COMPOSITE_BATCH:
+            case COMPOSITE_TREE:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    private static boolean isCompositeSObjectCollectionsOperation(OperationName operationName) {
+        switch (operationName) {
+            case COMPOSITE_CREATE_SOBJECT_COLLECTIONS:
+            case COMPOSITE_UPDATE_SOBJECT_COLLECTIONS:
+            case COMPOSITE_UPSERT_SOBJECT_COLLECTIONS:
+            case COMPOSITE_RETRIEVE_SOBJECT_COLLECTIONS:
+            case COMPOSITE_DELETE_SOBJECT_COLLECTIONS:
                 return true;
             default:
                 return false;
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/DeleteSObjectResult.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/DeleteSObjectResult.java
new file mode 100644
index 0000000..e96e4a3
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/DeleteSObjectResult.java
@@ -0,0 +1,55 @@
+/*
+ * 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.salesforce.api.dto;
+
+import java.util.List;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import com.thoughtworks.xstream.annotations.XStreamImplicit;
+
+@XStreamAlias("Result")
+public class DeleteSObjectResult extends AbstractDTOBase {
+
+    private String id;
+    @XStreamImplicit
+    private List<RestError> errors;
+    private Boolean success;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public List<RestError> getErrors() {
+        return errors;
+    }
+
+    public void setErrors(List<RestError> errors) {
+        this.errors = errors;
+    }
+
+    public Boolean getSuccess() {
+        return success;
+    }
+
+    public void setSuccess(Boolean success) {
+        this.success = success;
+    }
+}
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SaveSObjectResult.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SaveSObjectResult.java
new file mode 100644
index 0000000..355d031
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/SaveSObjectResult.java
@@ -0,0 +1,55 @@
+/*
+ * 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.salesforce.api.dto;
+
+import java.util.List;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import com.thoughtworks.xstream.annotations.XStreamImplicit;
+
+@XStreamAlias("Result")
+public class SaveSObjectResult extends AbstractDTOBase {
+
+    private String id;
+    @XStreamImplicit
+    private List<RestError> errors;
+    private Boolean success;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public List<RestError> getErrors() {
+        return errors;
+    }
+
+    public void setErrors(List<RestError> errors) {
+        this.errors = errors;
+    }
+
+    public Boolean getSuccess() {
+        return success;
+    }
+
+    public void setSuccess(Boolean success) {
+        this.success = success;
+    }
+}
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/composite/SObjectCollection.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/composite/SObjectCollection.java
new file mode 100644
index 0000000..ca8f937
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/composite/SObjectCollection.java
@@ -0,0 +1,49 @@
+/*
+ * 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.salesforce.api.dto.composite;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import org.apache.camel.component.salesforce.api.dto.AbstractDescribedSObjectBase;
+
+@XStreamAlias("batch")
+public class SObjectCollection implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private boolean allOrNone = false;
+    private List<AbstractDescribedSObjectBase> records = new ArrayList<>();
+
+    public boolean isAllOrNone() {
+        return allOrNone;
+    }
+
+    public void setAllOrNone(boolean allOrNone) {
+        this.allOrNone = allOrNone;
+    }
+
+    public List<AbstractDescribedSObjectBase> getRecords() {
+        return records;
+    }
+
+    public void setRecords(List<AbstractDescribedSObjectBase> records) {
+        this.records = records;
+    }
+}
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java
index f786de1..086cef8 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java
@@ -93,9 +93,16 @@ public enum OperationName {
     APPROVALS("approvals"),
 
     // Composite API
-    COMPOSITE_TREE("composite-tree"),
+    COMPOSITE("composite"),
     COMPOSITE_BATCH("composite-batch"),
-    COMPOSITE("composite");
+    COMPOSITE_TREE("composite-tree"),
+
+    // Composite sObject Collections API
+    COMPOSITE_CREATE_SOBJECT_COLLECTIONS("compositeCreateSObjectCollections"),
+    COMPOSITE_UPDATE_SOBJECT_COLLECTIONS("compositeUpdateSObjectCollections"),
+    COMPOSITE_UPSERT_SOBJECT_COLLECTIONS("compositeUpsertSObjectCollections"),
+    COMPOSITE_RETRIEVE_SOBJECT_COLLECTIONS("compositeRetrieveSObjectCollections"),
+    COMPOSITE_DELETE_SOBJECT_COLLECTIONS("compositeDeleteSObjectCollections");
 
     private final String value;
 
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
index de10085..da043d8 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/AbstractClientBase.java
@@ -277,6 +277,12 @@ public abstract class AbstractClientBase extends ServiceSupport
     }
 
     final List<RestError> readErrorsFrom(
+            final InputStream responseContent, final PayloadFormat format, final ObjectMapper objectMapper)
+            throws IOException, JsonParseException, JsonMappingException {
+        return readErrorsFrom(responseContent, format, objectMapper, null);
+    }
+
+    final List<RestError> readErrorsFrom(
             final InputStream responseContent, final PayloadFormat format, final ObjectMapper objectMapper,
             final XStream xStream)
             throws IOException, JsonParseException, JsonMappingException {
@@ -345,7 +351,6 @@ public abstract class AbstractClientBase extends ServiceSupport
                 }
             }
         }
-
         return answer;
     }
 }
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/CompositeSObjectCollectionsApiClient.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/CompositeSObjectCollectionsApiClient.java
new file mode 100644
index 0000000..e3e9934
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/CompositeSObjectCollectionsApiClient.java
@@ -0,0 +1,51 @@
+/*
+ * 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.salesforce.internal.client;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.api.dto.DeleteSObjectResult;
+import org.apache.camel.component.salesforce.api.dto.SaveSObjectResult;
+import org.apache.camel.component.salesforce.api.dto.composite.SObjectCollection;
+import org.apache.camel.component.salesforce.internal.dto.composite.RetrieveSObjectCollectionsDto;
+
+public interface CompositeSObjectCollectionsApiClient {
+
+    @FunctionalInterface
+    interface ResponseCallback<T> {
+        void onResponse(Optional<T> body, Map<String, String> headers, SalesforceException exception);
+    }
+
+    <T> void submitRetrieveCompositeCollections(
+            RetrieveSObjectCollectionsDto retrieveDto, Map<String, List<String>> headers,
+            ResponseCallback<List<T>> callback, String sObjectName,
+            Class<T> returnType)
+            throws SalesforceException;
+
+    void submitCompositeCollections(
+            SObjectCollection collection, Map<String, List<String>> headers,
+            ResponseCallback<List<SaveSObjectResult>> callback, String sObjectName, String externalIdFieldName,
+            String method)
+            throws SalesforceException;
+
+    void submitDeleteCompositeCollections(
+            List<String> ids, Boolean allOrNone, Map<String, List<String>> headers,
+            ResponseCallback<List<DeleteSObjectResult>> callback);
+}
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultCompositeApiClient.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultCompositeApiClient.java
index 0358122..2a492e7 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultCompositeApiClient.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultCompositeApiClient.java
@@ -28,6 +28,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.ObjectReader;
 import com.fasterxml.jackson.databind.ObjectWriter;
+import com.fasterxml.jackson.databind.type.CollectionType;
 import com.thoughtworks.xstream.XStream;
 import com.thoughtworks.xstream.XStreamException;
 import org.apache.camel.component.salesforce.SalesforceEndpointConfig;
@@ -71,10 +72,12 @@ public class DefaultCompositeApiClient extends AbstractClientBase implements Com
 
     private final XStream xStreamCompositeTree;
 
-    public DefaultCompositeApiClient(final SalesforceEndpointConfig configuration, final PayloadFormat format,
+    public DefaultCompositeApiClient(
+                                     final SalesforceEndpointConfig configuration, final PayloadFormat format,
                                      final String version, final SalesforceSession session,
                                      final SalesforceHttpClient httpClient, final SalesforceLoginConfig loginConfig)
                                                                                                                      throws SalesforceException {
+
         super(version, session, httpClient, loginConfig);
         this.format = format;
 
@@ -208,6 +211,11 @@ public class DefaultCompositeApiClient extends AbstractClientBase implements Com
         return jsonReaderFor(expectedType).readValue(responseStream);
     }
 
+    <T> List<T> fromJsonList(final Class<T> expectedType, final InputStream responseStream) throws IOException {
+        final CollectionType collectionType = mapper.getTypeFactory().constructCollectionType(List.class, expectedType);
+        return mapper.readValue(responseStream, collectionType);
+    }
+
     ObjectReader jsonReaderFor(final Class<?> type) {
         return mapper.readerFor(type);
     }
@@ -329,5 +337,4 @@ public class DefaultCompositeApiClient extends AbstractClientBase implements Com
 
         return new ByteArrayInputStream(out.toByteArray());
     }
-
 }
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultCompositeSObjectCollectionsApiClient.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultCompositeSObjectCollectionsApiClient.java
new file mode 100644
index 0000000..794b4bb
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultCompositeSObjectCollectionsApiClient.java
@@ -0,0 +1,232 @@
+/*
+ * 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.salesforce.internal.client;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectWriter;
+import com.fasterxml.jackson.databind.type.CollectionType;
+import org.apache.camel.component.salesforce.SalesforceEndpointConfig;
+import org.apache.camel.component.salesforce.SalesforceHttpClient;
+import org.apache.camel.component.salesforce.SalesforceLoginConfig;
+import org.apache.camel.component.salesforce.api.NoSuchSObjectException;
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.api.dto.DeleteSObjectResult;
+import org.apache.camel.component.salesforce.api.dto.RestError;
+import org.apache.camel.component.salesforce.api.dto.SaveSObjectResult;
+import org.apache.camel.component.salesforce.api.dto.composite.SObjectCollection;
+import org.apache.camel.component.salesforce.api.utils.JsonUtils;
+import org.apache.camel.component.salesforce.internal.PayloadFormat;
+import org.apache.camel.component.salesforce.internal.SalesforceSession;
+import org.apache.camel.component.salesforce.internal.dto.composite.RetrieveSObjectCollectionsDto;
+import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.eclipse.jetty.client.api.ContentProvider;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.client.api.Response;
+import org.eclipse.jetty.client.util.InputStreamContentProvider;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpStatus;
+
+public class DefaultCompositeSObjectCollectionsApiClient extends AbstractClientBase
+        implements CompositeSObjectCollectionsApiClient {
+
+    private final ObjectMapper mapper;
+
+    public DefaultCompositeSObjectCollectionsApiClient(final SalesforceEndpointConfig configuration,
+                                                       final String version, final SalesforceSession session,
+                                                       final SalesforceHttpClient httpClient,
+                                                       final SalesforceLoginConfig loginConfig)
+                                                                                                throws SalesforceException {
+        super(version, session, httpClient, loginConfig);
+
+        if (configuration.getObjectMapper() != null) {
+            mapper = configuration.getObjectMapper();
+        } else {
+            mapper = JsonUtils.createObjectMapper();
+        }
+    }
+
+    @Override
+    public <T> void submitRetrieveCompositeCollections(
+            final RetrieveSObjectCollectionsDto retrieveDto, final Map<String, List<String>> headers,
+            final ResponseCallback<List<T>> callback, final String sObjectName,
+            Class<T> sobjectType)
+            throws SalesforceException {
+
+        String url = versionUrl() + "composite/sobjects/" + sObjectName;
+        Request request = createRequest("POST", url, headers);
+
+        final ContentProvider content = serialize(retrieveDto);
+        request.content(content);
+
+        doHttpRequest(request, new ClientResponseCallback() {
+            @Override
+            public void onResponse(InputStream response, Map<String, String> headers, SalesforceException ex) {
+                callback.onResponse(
+                        tryToReadListResponse(
+                                sobjectType, response),
+                        headers,
+                        ex);
+            }
+        });
+    }
+
+    @Override
+    public void submitCompositeCollections(
+            final SObjectCollection collection, final Map<String, List<String>> headers,
+            final ResponseCallback<List<SaveSObjectResult>> callback, final String sObjectName,
+            final String externalIdFieldName, final String method)
+            throws SalesforceException {
+
+        String url = versionUrl() + "composite/sobjects";
+        if (sObjectName != null) {
+            url = url + "/" + sObjectName;
+            if (externalIdFieldName != null) {
+                url = url + "/" + externalIdFieldName;
+            }
+        }
+        Request request = createRequest(method, url, headers);
+
+        final ContentProvider content = serialize(collection);
+        request.content(content);
+
+        doHttpRequest(request, new ClientResponseCallback() {
+            @Override
+            public void onResponse(InputStream response, Map<String, String> headers, SalesforceException ex) {
+                callback.onResponse(
+                        tryToReadListResponse(SaveSObjectResult.class, response),
+                        headers, ex);
+            }
+        });
+    }
+
+    @Override
+    public void submitDeleteCompositeCollections(
+            List<String> ids, Boolean allOrNone, final Map<String, List<String>> headers,
+            final ResponseCallback<List<DeleteSObjectResult>> callback) {
+
+        String url = versionUrl() + "composite/sobjects";
+        Request request = createRequest("DELETE", url, headers)
+                .param("ids", String.join(",", ids))
+                .param("allOrNone", allOrNone.toString());
+
+        doHttpRequest(request, new ClientResponseCallback() {
+            @Override
+            public void onResponse(InputStream response, Map<String, String> headers, SalesforceException ex) {
+                callback.onResponse(
+                        tryToReadListResponse(DeleteSObjectResult.class, response),
+                        headers, ex);
+            }
+        });
+    }
+
+    @Override
+    protected SalesforceException createRestException(final Response response, final InputStream responseContent) {
+        final List<RestError> errors;
+        try {
+            errors = readErrorsFrom(responseContent, PayloadFormat.JSON, mapper);
+        } catch (final IOException e) {
+            return new SalesforceException("Unable to read error response", e);
+        }
+
+        final int status = response.getStatus();
+        if (status == HttpStatus.NOT_FOUND_404) {
+            return new NoSuchSObjectException(errors);
+        }
+        final String reason = response.getReason();
+        return new SalesforceException("Unexpected error: " + reason, status);
+    }
+
+    @Override
+    protected void setAccessToken(final Request request) {
+        request.getHeaders().put("Authorization", "Bearer " + accessToken);
+    }
+
+    private Request createRequest(final String method, final String url, final Map<String, List<String>> headers) {
+        final Request request = getRequest(method, url, headers);
+        return populateRequest(request);
+    }
+
+    private Request populateRequest(Request request) {
+        // setup authorization
+        setAccessToken(request);
+
+        request.header(HttpHeader.CONTENT_TYPE, APPLICATION_JSON_UTF8);
+        request.header(HttpHeader.ACCEPT, APPLICATION_JSON_UTF8);
+
+        return request;
+    }
+
+    private <T> List<T> fromJsonList(final Class<T> expectedType, final InputStream responseStream) throws IOException {
+        final CollectionType collectionType = mapper.getTypeFactory().constructCollectionType(List.class, expectedType);
+        return mapper.readValue(responseStream, collectionType);
+    }
+
+    private ObjectWriter jsonWriterFor(final Object obj) {
+        final Class<?> type = obj.getClass();
+
+        return mapper.writerFor(type);
+    }
+
+    private ContentProvider serialize(final Object body, final Class<?>... additionalTypes)
+            throws SalesforceException {
+        return new InputStreamContentProvider(toJson(body));
+    }
+
+    private String servicesDataUrl() {
+        return instanceUrl + "/services/data/";
+    }
+
+    private InputStream toJson(final Object obj) throws SalesforceException {
+        byte[] jsonBytes;
+        try {
+            jsonBytes = jsonWriterFor(obj).writeValueAsBytes(obj);
+        } catch (final JsonProcessingException e) {
+            throw new SalesforceException("Unable to serialize given SObjectTree to JSON", e);
+        }
+
+        return new ByteArrayInputStream(jsonBytes);
+    }
+
+    private <T> Optional<List<T>> tryToReadListResponse(
+            final Class<T> expectedType, final InputStream responseStream) {
+        if (responseStream == null) {
+            return Optional.empty();
+        }
+        try {
+            return Optional.of(fromJsonList(expectedType, responseStream));
+        } catch (IOException e) {
+            log.warn("Unable to read response from the Composite API", e);
+            return Optional.empty();
+        } finally {
+            IOHelper.close(responseStream);
+        }
+    }
+
+    private String versionUrl() {
+        ObjectHelper.notNull(version, "version");
+        return servicesDataUrl() + "v" + version + "/";
+    }
+}
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/composite/RetrieveSObjectCollectionsDto.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/composite/RetrieveSObjectCollectionsDto.java
new file mode 100644
index 0000000..7284e1c
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/dto/composite/RetrieveSObjectCollectionsDto.java
@@ -0,0 +1,39 @@
+package org.apache.camel.component.salesforce.internal.dto.composite;
+
+import java.io.Serializable;
+import java.util.List;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+
+@XStreamAlias("batch")
+public class RetrieveSObjectCollectionsDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private List<String> ids;
+    private List<String> fields;
+
+    public RetrieveSObjectCollectionsDto() {
+    }
+
+    public RetrieveSObjectCollectionsDto(List<String> ids, List<String> fields) {
+        this.ids = ids;
+        this.fields = fields;
+    }
+
+    public List<String> getIds() {
+        return ids;
+    }
+
+    public void setIds(List<String> ids) {
+        this.ids = ids;
+    }
+
+    public List<String> getFields() {
+        return fields;
+    }
+
+    public void setFields(List<String> fields) {
+        this.fields = fields;
+    }
+}
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessor.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessor.java
index 1b21874..c2f8bd7 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessor.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessor.java
@@ -51,7 +51,6 @@ import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.APE
 import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.APEX_QUERY_PARAM_PREFIX;
 import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.APEX_URL;
 import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.SOBJECT_BLOB_FIELD_NAME;
-import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.SOBJECT_CLASS;
 import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.SOBJECT_EXT_ID_NAME;
 import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.SOBJECT_EXT_ID_VALUE;
 import static org.apache.camel.component.salesforce.SalesforceEndpointConfig.SOBJECT_FIELDS;
@@ -66,7 +65,6 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor
     private static final Pattern URL_TEMPLATE = Pattern.compile("\\{([^\\{\\}]+)\\}");
 
     private RestClient restClient;
-    private Map<String, Class<?>> classMap;
     private NotFoundBehaviour notFoundBehaviour;
 
     // used in unit tests
@@ -93,10 +91,6 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor
         if (restClient == null) {
             this.restClient = salesforceComponent.createRestClientFor(endpoint);
         }
-        if (classMap == null) {
-            this.classMap = endpoint.getComponent().getClassMap();
-        }
-
         ServiceHelper.startService(restClient);
     }
 
@@ -746,25 +740,7 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor
             return;
         }
 
-        Class<?> sObjectClass;
-
-        if (sObjectName != null) {
-            // lookup class from class map
-            sObjectClass = classMap.get(sObjectName);
-            if (null == sObjectClass) {
-                throw new SalesforceException(String.format("No class found for SObject %s", sObjectName), null);
-            }
-
-        } else {
-
-            // use custom response class property
-            final String className = getParameter(SOBJECT_CLASS, exchange, IGNORE_BODY, NOT_OPTIONAL);
-            try {
-                sObjectClass = endpoint.getComponent().getCamelContext().getClassResolver().resolveMandatoryClass(className);
-            } catch (ClassNotFoundException e) {
-                throw new SalesforceException(String.format("SObject class not found %s, %s", className, e.getMessage()), e);
-            }
-        }
+        Class<?> sObjectClass = getSObjectClass(sObjectName, exchange);
         exchange.setProperty(RESPONSE_CLASS, sObjectClass);
     }
 
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractSalesforceProcessor.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractSalesforceProcessor.java
index f76ec81..d028ed6 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractSalesforceProcessor.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractSalesforceProcessor.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.component.salesforce.internal.processor;
 
+import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.camel.AsyncCallback;
@@ -24,6 +26,7 @@ import org.apache.camel.Message;
 import org.apache.camel.NoTypeConversionAvailableException;
 import org.apache.camel.component.salesforce.SalesforceComponent;
 import org.apache.camel.component.salesforce.SalesforceEndpoint;
+import org.apache.camel.component.salesforce.SalesforceEndpointConfig;
 import org.apache.camel.component.salesforce.SalesforceHttpClient;
 import org.apache.camel.component.salesforce.SalesforceLoginConfig;
 import org.apache.camel.component.salesforce.api.SalesforceException;
@@ -49,6 +52,8 @@ public abstract class AbstractSalesforceProcessor extends ServiceSupport impleme
     protected SalesforceSession session;
     protected SalesforceHttpClient httpClient;
     protected SalesforceLoginConfig loginConfig;
+    protected Map<String, Class<?>> classMap;
+
     protected boolean rawPayload;
 
     public AbstractSalesforceProcessor(final SalesforceEndpoint endpoint) {
@@ -70,6 +75,9 @@ public abstract class AbstractSalesforceProcessor extends ServiceSupport impleme
         if (httpClient == null) {
             httpClient = component.getHttpClient();
         }
+        if (classMap == null) {
+            this.classMap = endpoint.getComponent().getClassMap();
+        }
     }
 
     @Override
@@ -151,4 +159,36 @@ public abstract class AbstractSalesforceProcessor extends ServiceSupport impleme
         return propValue;
     }
 
+    // Given a parameter value as List or a CSV String, will return a List<String>
+    protected List<String> getListParameter(
+            final String propName, final Exchange exchange, final boolean convertInBody, final boolean optional)
+            throws SalesforceException {
+
+        Object val = getParameter(propName, exchange, convertInBody, optional, Object.class);
+        if (val instanceof String) {
+            return Arrays.asList(((String) val).split(","));
+        }
+        if (val instanceof List) {
+            return (List<String>) val;
+        } else {
+            throw new SalesforceException("Expected " + propName + " parameter to be a List or CSV String.", 0);
+        }
+    }
+
+    protected Class<?> getSObjectClass(String sObjectName, Exchange exchange) throws SalesforceException {
+        Class<?> sObjectClass = null;
+        if (sObjectName != null) {
+            sObjectClass = classMap.get(sObjectName);
+        }
+        if (sObjectClass == null) {
+            final String className = getParameter(SalesforceEndpointConfig.SOBJECT_CLASS, exchange, IGNORE_BODY, NOT_OPTIONAL);
+            try {
+                sObjectClass = endpoint.getComponent().getCamelContext().getClassResolver().resolveMandatoryClass(className);
+            } catch (ClassNotFoundException e) {
+                throw new SalesforceException(
+                        String.format("SObject class not found %s or by sObjectName %s", className, sObjectName), e);
+            }
+        }
+        return sObjectClass;
+    }
 }
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/CompositeSObjectCollectionsProcessor.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/CompositeSObjectCollectionsProcessor.java
new file mode 100644
index 0000000..d811f5b
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/CompositeSObjectCollectionsProcessor.java
@@ -0,0 +1,202 @@
+/*
+ * 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.salesforce.internal.processor;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.camel.AsyncCallback;
+import org.apache.camel.Exchange;
+import org.apache.camel.InvalidPayloadException;
+import org.apache.camel.Message;
+import org.apache.camel.component.salesforce.SalesforceEndpoint;
+import org.apache.camel.component.salesforce.SalesforceEndpointConfig;
+import org.apache.camel.component.salesforce.api.SalesforceException;
+import org.apache.camel.component.salesforce.api.dto.AbstractDescribedSObjectBase;
+import org.apache.camel.component.salesforce.api.dto.composite.SObjectCollection;
+import org.apache.camel.component.salesforce.internal.PayloadFormat;
+import org.apache.camel.component.salesforce.internal.client.CompositeSObjectCollectionsApiClient;
+import org.apache.camel.component.salesforce.internal.client.DefaultCompositeSObjectCollectionsApiClient;
+import org.apache.camel.component.salesforce.internal.dto.composite.RetrieveSObjectCollectionsDto;
+import org.apache.camel.support.service.ServiceHelper;
+
+public class CompositeSObjectCollectionsProcessor extends AbstractSalesforceProcessor {
+
+    private CompositeSObjectCollectionsApiClient compositeClient;
+    private Map<String, Class<?>> classMap;
+
+    public CompositeSObjectCollectionsProcessor(final SalesforceEndpoint endpoint) {
+        super(endpoint);
+
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+        final SalesforceEndpointConfig configuration = endpoint.getConfiguration();
+        final String apiVersion = configuration.getApiVersion();
+
+        final PayloadFormat format = configuration.getFormat();
+        if (format != PayloadFormat.JSON) {
+            throw new SalesforceException("The Composite SObject Collections operations only support JSON format.", 0);
+        }
+        compositeClient = new DefaultCompositeSObjectCollectionsApiClient(
+                configuration, apiVersion, session, httpClient, loginConfig);
+
+        if (classMap == null) {
+            this.classMap = endpoint.getComponent().getClassMap();
+        }
+        ServiceHelper.startService(compositeClient);
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        super.doStop();
+        ServiceHelper.stopService(compositeClient);
+    }
+
+    @Override
+    public boolean process(final Exchange exchange, final AsyncCallback callback) {
+        try {
+            switch (operationName) {
+                case COMPOSITE_CREATE_SOBJECT_COLLECTIONS:
+                    return processCreateSObjectCollections(exchange, callback);
+                case COMPOSITE_UPDATE_SOBJECT_COLLECTIONS:
+                    return processUpdateSObjectCollections(exchange, callback);
+                case COMPOSITE_UPSERT_SOBJECT_COLLECTIONS:
+                    return processUpsertSObjectCollections(exchange, callback);
+                case COMPOSITE_RETRIEVE_SOBJECT_COLLECTIONS:
+                    return processRetrieveSObjectCollections(exchange, callback);
+                case COMPOSITE_DELETE_SOBJECT_COLLECTIONS:
+                    return processDeleteSObjectCollections(exchange, callback);
+                default:
+                    throw new SalesforceException("Unknown operation name: " + operationName.value(), null);
+            }
+        } catch (final SalesforceException e) {
+            return processException(exchange, callback, e);
+        } catch (final RuntimeException e) {
+            final SalesforceException exception = new SalesforceException(
+                    String.format("Unexpected Error processing %s: \"%s\"", operationName.value(), e.getMessage()), e);
+            return processException(exchange, callback, exception);
+        }
+    }
+
+    private boolean processRetrieveSObjectCollections(Exchange exchange, AsyncCallback callback)
+            throws SalesforceException {
+        List<String> ids = getListParameter(SalesforceEndpointConfig.SOBJECT_IDS, exchange, USE_BODY, NOT_OPTIONAL);
+        List<String> fields = getListParameter(SalesforceEndpointConfig.SOBJECT_FIELDS, exchange, USE_BODY, NOT_OPTIONAL);
+        String sObjectName = getParameter(SalesforceEndpointConfig.SOBJECT_NAME, exchange, IGNORE_BODY, IS_OPTIONAL);
+
+        // gets class by sObjectName if not null, otherwise tries the SOBJECT_CLASS option
+        Class<?> sObjectClass = getSObjectClass(sObjectName, exchange);
+
+        RetrieveSObjectCollectionsDto request = new RetrieveSObjectCollectionsDto(ids, fields);
+        compositeClient.submitRetrieveCompositeCollections(request, determineHeaders(exchange),
+                (response, responseHeaders, exception) -> processResponse(exchange, response,
+                        responseHeaders, exception, callback),
+                sObjectName, sObjectClass);
+        return false;
+    }
+
+    private boolean processCreateSObjectCollections(final Exchange exchange, final AsyncCallback callback)
+            throws SalesforceException {
+        SObjectCollection collection = buildSObjectCollection(exchange);
+        compositeClient.submitCompositeCollections(collection, determineHeaders(exchange),
+                (response, responseHeaders, exception) -> processResponse(exchange, response, responseHeaders,
+                        exception, callback),
+                null, null, "POST");
+        return false;
+    }
+
+    private boolean processUpdateSObjectCollections(final Exchange exchange, final AsyncCallback callback)
+            throws SalesforceException {
+        final SObjectCollection collection = buildSObjectCollection(exchange);
+        compositeClient.submitCompositeCollections(collection, determineHeaders(exchange),
+                (response, responseHeaders, exception) -> processResponse(exchange, response, responseHeaders,
+                        exception, callback),
+                null, null, "PATCH");
+        return false;
+    }
+
+    private boolean processUpsertSObjectCollections(final Exchange exchange, final AsyncCallback callback)
+            throws SalesforceException {
+        final SObjectCollection collection = buildSObjectCollection(exchange);
+        String externalIdFieldName
+                = getParameter(SalesforceEndpointConfig.SOBJECT_EXT_ID_NAME, exchange, IGNORE_BODY, NOT_OPTIONAL);
+        String sObjectName = getParameter(SalesforceEndpointConfig.SOBJECT_NAME, exchange, IGNORE_BODY, NOT_OPTIONAL);
+        compositeClient.submitCompositeCollections(collection, determineHeaders(exchange),
+                (response, responseHeaders, exception) -> processResponse(exchange, response, responseHeaders,
+                        exception, callback),
+                sObjectName, externalIdFieldName, "PATCH");
+
+        return false;
+    }
+
+    private boolean processDeleteSObjectCollections(final Exchange exchange, final AsyncCallback callback)
+            throws SalesforceException {
+        List<String> ids = getListParameter(SalesforceEndpointConfig.SOBJECT_IDS, exchange, USE_BODY, NOT_OPTIONAL);
+        boolean allOrNone = Boolean.parseBoolean(
+                getParameter(SalesforceEndpointConfig.ALL_OR_NONE, exchange, USE_BODY, IS_OPTIONAL));
+        compositeClient.submitDeleteCompositeCollections(ids, allOrNone, determineHeaders(exchange),
+                (response, responseHeaders, exception) -> processResponse(exchange, response,
+                        responseHeaders, exception, callback));
+        return false;
+    }
+
+    private SObjectCollection buildSObjectCollection(Exchange exchange) throws SalesforceException {
+        final List<AbstractDescribedSObjectBase> body;
+        final Message in = exchange.getIn();
+        try {
+            body = (List<AbstractDescribedSObjectBase>) in.getMandatoryBody();
+        } catch (final InvalidPayloadException e) {
+            throw new SalesforceException(e);
+        }
+        SObjectCollection collection = new SObjectCollection();
+        collection.setRecords(body);
+        boolean allOrNone = Boolean.parseBoolean(
+                getParameter(SalesforceEndpointConfig.ALL_OR_NONE, exchange, USE_BODY, IS_OPTIONAL));
+        collection.setAllOrNone(allOrNone);
+        return collection;
+    }
+
+    private void processResponse(
+            final Exchange exchange, final Optional<? extends List<?>> responseBody, final Map<String, String> headers,
+            final SalesforceException exception, final AsyncCallback callback) {
+        try {
+            if (!responseBody.isPresent()) {
+                exchange.setException(exception);
+            }
+            final Message in = exchange.getIn();
+            final Message out = exchange.getOut();
+
+            final List<?> response = responseBody.get();
+
+            out.copyFromWithNewBody(in, response);
+            out.getHeaders().putAll(headers);
+        } finally {
+            callback.done(false);
+        }
+    }
+
+    private boolean processException(final Exchange exchange, final AsyncCallback callback, final Exception e) {
+        exchange.setException(e);
+        callback.done(true);
+
+        return true;
+    }
+}
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/CompositeApiCollectionsIntegrationTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/CompositeApiCollectionsIntegrationTest.java
new file mode 100644
index 0000000..41c7207
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/CompositeApiCollectionsIntegrationTest.java
@@ -0,0 +1,195 @@
+/*
+ * 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.salesforce;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.salesforce.api.dto.AbstractDescribedSObjectBase;
+import org.apache.camel.component.salesforce.api.dto.CreateSObjectResult;
+import org.apache.camel.component.salesforce.api.dto.DeleteSObjectResult;
+import org.apache.camel.component.salesforce.api.dto.SaveSObjectResult;
+import org.apache.camel.component.salesforce.dto.generated.Account;
+import org.apache.camel.test.junit5.params.Parameter;
+import org.apache.camel.test.junit5.params.Parameterized;
+import org.apache.camel.test.junit5.params.Parameters;
+import org.apache.camel.test.junit5.params.Test;
+import org.junit.jupiter.api.AfterEach;
+
+import static org.apache.camel.language.constant.ConstantLanguage.constant;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@SuppressWarnings("unchecked")
+@Parameterized
+public class CompositeApiCollectionsIntegrationTest extends AbstractSalesforceTestBase {
+
+    private static final Set<String> VERSIONS = new HashSet<>(Arrays.asList("46.0", "50.0"));
+
+    @Parameter
+    private String version;
+
+    @AfterEach
+    public void removeRecords() {
+        template.request("direct:deleteCompositeAccounts", null);
+    }
+
+    @Test
+    public void retrieve() {
+        final String accountId = createAccount();
+
+        List<AbstractDescribedSObjectBase> result
+                = (List<AbstractDescribedSObjectBase>) fluentTemplate.to("salesforce:compositeRetrieveSObjectCollections")
+                        .withHeader("sObjectIds", Collections.singletonList(accountId))
+                        .withHeader("sObjectFields", Arrays.asList("Id", "Name"))
+                        .withHeader("sObjectName", "Account")
+                        .request();
+        assertNotNull(result, "Response was null.");
+        assertEquals(1, result.size());
+    }
+
+    @Test
+    public void delete() {
+        final String accountId = createAccount();
+        final String account2Id = createAccount();
+        final List<String> ids = Arrays.asList(accountId, account2Id, "001000000000000000");
+        List<DeleteSObjectResult> result
+                = (List<DeleteSObjectResult>) fluentTemplate.to("salesforce:compositeDeleteSObjectCollections")
+                        .withHeader("sObjectIds", ids)
+                        .request();
+        assertNotNull(result, "Response was null.");
+        assertEquals(3, result.size());
+        assertTrue(result.get(0).getSuccess());
+        assertTrue(result.get(1).getSuccess());
+        assertFalse(result.get(2).getSuccess());
+    }
+
+    @Test
+    public void deleteAllOrNone() {
+        final String accountId = createAccount();
+        final List<String> ids = Arrays.asList(accountId, "001000000000000000");
+        List<DeleteSObjectResult> result
+                = (List<DeleteSObjectResult>) fluentTemplate.to("salesforce:compositeDeleteSObjectCollections")
+                        .withHeader("sObjectIds", ids)
+                        .withHeader("allOrNone", constant(true))
+                        .request();
+        assertNotNull(result, "Response was null.");
+        assertEquals(2, result.size());
+        assertFalse(result.get(0).getSuccess());
+        assertFalse(result.get(1).getSuccess());
+    }
+
+    @Test
+    public void create() {
+        Account account1 = new Account();
+        account1.setName("Account created from Composite Collections API");
+
+        Account account2 = new Account();
+        final List<Account> accounts = Arrays.asList(account1, account2);
+
+        List<SaveSObjectResult> result
+                = (List<SaveSObjectResult>) template.requestBody(
+                        "salesforce:compositeCreateSObjectCollections", accounts);
+        assertNotNull(result, "Response was null.");
+        assertEquals(2, result.size());
+        assertTrue(result.get(0).getSuccess());
+        assertFalse(result.get(1).getSuccess());
+    }
+
+    @Test
+    public void createAllOrNone() {
+        Account account1 = new Account();
+        account1.setName("Account created from Composite Collections API");
+
+        Account account2 = new Account();
+        final List<Account> accounts = Arrays.asList(account1, account2);
+
+        List<SaveSObjectResult> result
+                = (List<SaveSObjectResult>) template.requestBody(
+                        "salesforce:compositeCreateSObjectCollections", accounts);
+        assertNotNull(result, "Response was null.");
+        assertEquals(2, result.size());
+        assertTrue(result.get(0).getSuccess());
+        assertFalse(result.get(1).getSuccess());
+    }
+
+    @Test
+    public void update() {
+        final String accountId = createAccount();
+        Account account = new Account();
+        account.setId(accountId);
+        final List<Account> accounts = Collections.singletonList(account);
+
+        List<SaveSObjectResult> result = (List<SaveSObjectResult>) template.requestBody(
+                "salesforce:compositeUpdateSObjectCollections", accounts);
+        assertNotNull(result, "Response was null.");
+        assertTrue(result.get(0).getSuccess());
+    }
+
+    @Test
+    public void upsert() {
+        Account account = new Account();
+        account.setName("Account created from Composite Collections API");
+        account.setExternal_Id__c("AAA");
+        final List<Account> accounts = Collections.singletonList(account);
+
+        List<SaveSObjectResult> result = (List<SaveSObjectResult>) template.requestBody(
+                "salesforce:compositeUpsertSObjectCollections?sObjectName=Account&sObjectIdName=External_Id__c",
+                accounts);
+        assertNotNull(result, "Response was null.");
+        assertTrue(result.get(0).getSuccess());
+    }
+
+    @Override
+    protected String salesforceApiVersionToUse() {
+        return version;
+    }
+
+    @Override
+    protected RouteBuilder doCreateRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:deleteCompositeAccounts")
+                        .to("salesforce:query?sObjectClass=" + Account.class.getName()
+                                + "&sObjectQuery=SELECT Id FROM Account WHERE Name = 'Account created from Composite Collections API'")
+                        .split(simple("${body.records}")).setHeader("sObjectId", simple("${body.id}"))
+                        .to("salesforce:deleteSObject?sObjectName=Account").end();
+            }
+        };
+    }
+
+    @Parameters(name = "version = {0}")
+    public static Iterable<Object[]> versions() {
+        return VERSIONS.stream().map(v -> new Object[] { v }).collect(Collectors.toList());
+    }
+
+    private String createAccount() {
+        Account account = new Account();
+        account.setName("Account created from Composite Collections API");
+        final CreateSObjectResult createResult
+                = template.requestBody("salesforce:createSObject", account, CreateSObjectResult.class);
+        return createResult.getId();
+    }
+}
diff --git a/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SalesforceComponentBuilderFactory.java b/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SalesforceComponentBuilderFactory.java
index 240d81c..56bdcfd 100644
--- a/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SalesforceComponentBuilderFactory.java
+++ b/core/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/SalesforceComponentBuilderFactory.java
@@ -873,6 +873,22 @@ public interface SalesforceComponentBuilderFactory {
             return this;
         }
         /**
+         * Composite API option to indicate to rollback all records if any are
+         * not successful.
+         * 
+         * The option is a: &lt;code&gt;boolean&lt;/code&gt; type.
+         * 
+         * Default: false
+         * Group: producer
+         * 
+         * @param allOrNone the value to set
+         * @return the dsl builder
+         */
+        default SalesforceComponentBuilder allOrNone(boolean allOrNone) {
+            doSetProperty("allOrNone", allOrNone);
+            return this;
+        }
+        /**
          * APEX method URL.
          * 
          * The option is a: &lt;code&gt;java.lang.String&lt;/code&gt; type.
@@ -1423,6 +1439,7 @@ public interface SalesforceComponentBuilderFactory {
             case "httpClientProperties": ((SalesforceComponent) component).setHttpClientProperties((java.util.Map) value); return true;
             case "longPollingTransportProperties": ((SalesforceComponent) component).setLongPollingTransportProperties((java.util.Map) value); return true;
             case "bridgeErrorHandler": ((SalesforceComponent) component).setBridgeErrorHandler((boolean) value); return true;
+            case "allOrNone": getOrCreateConfiguration((SalesforceComponent) component).setAllOrNone((boolean) value); return true;
             case "apexUrl": getOrCreateConfiguration((SalesforceComponent) component).setApexUrl((java.lang.String) value); return true;
             case "compositeMethod": getOrCreateConfiguration((SalesforceComponent) component).setCompositeMethod((java.lang.String) value); return true;
             case "lazyStartProducer": ((SalesforceComponent) component).setLazyStartProducer((boolean) value); return true;
diff --git a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
index 719e0419..1c03d57 100644
--- a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
+++ b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
@@ -12547,7 +12547,7 @@ public class StaticEndpointBuilders {
      * 
      * Path parameter: operationName
      * The operation to use
-     * There are 59 enums and the value can be one of: getVersions,
+     * There are 64 enums and the value can be one of: getVersions,
      * getResources, getGlobalObjects, getBasicInfo, getDescription, getSObject,
      * createSObject, updateSObject, deleteSObject, getSObjectWithId,
      * upsertSObject, deleteSObjectWithId, getBlobField, query, queryMore,
@@ -12556,12 +12556,15 @@ public class StaticEndpointBuilders {
      * createBatchQuery, getQueryResultIds, getQueryResult, getRecentReports,
      * getReportDescription, executeSyncReport, executeAsyncReport,
      * getReportInstances, getReportResults, limits, approval, approvals,
-     * composite-tree, composite-batch, composite, bulk2GetAllJobs,
-     * bulk2CreateJob, bulk2GetJob, bulk2CreateBatch, bulk2CloseJob,
-     * bulk2AbortJob, bulk2DeleteJob, bulk2GetSuccessfulResults,
-     * bulk2GetFailedResults, bulk2GetUnprocessedRecords, bulk2CreateQueryJob,
-     * bulk2GetQueryJob, bulk2GetAllQueryJobs, bulk2GetQueryJobResults,
-     * bulk2AbortQueryJob, bulk2DeleteQueryJob
+     * composite-tree, composite-batch, composite,
+     * compositeRetrieveSObjectCollections, compositeCreateSObjectCollections,
+     * compositeUpdateSObjectCollections, compositeUpsertSObjectCollections,
+     * compositeDeleteSObjectCollections, bulk2GetAllJobs, bulk2CreateJob,
+     * bulk2GetJob, bulk2CreateBatch, bulk2CloseJob, bulk2AbortJob,
+     * bulk2DeleteJob, bulk2GetSuccessfulResults, bulk2GetFailedResults,
+     * bulk2GetUnprocessedRecords, bulk2CreateQueryJob, bulk2GetQueryJob,
+     * bulk2GetAllQueryJobs, bulk2GetQueryJobResults, bulk2AbortQueryJob,
+     * bulk2DeleteQueryJob
      * 
      * Path parameter: topicName
      * The name of the topic/channel to use
@@ -12585,7 +12588,7 @@ public class StaticEndpointBuilders {
      * 
      * Path parameter: operationName
      * The operation to use
-     * There are 59 enums and the value can be one of: getVersions,
+     * There are 64 enums and the value can be one of: getVersions,
      * getResources, getGlobalObjects, getBasicInfo, getDescription, getSObject,
      * createSObject, updateSObject, deleteSObject, getSObjectWithId,
      * upsertSObject, deleteSObjectWithId, getBlobField, query, queryMore,
@@ -12594,12 +12597,15 @@ public class StaticEndpointBuilders {
      * createBatchQuery, getQueryResultIds, getQueryResult, getRecentReports,
      * getReportDescription, executeSyncReport, executeAsyncReport,
      * getReportInstances, getReportResults, limits, approval, approvals,
-     * composite-tree, composite-batch, composite, bulk2GetAllJobs,
-     * bulk2CreateJob, bulk2GetJob, bulk2CreateBatch, bulk2CloseJob,
-     * bulk2AbortJob, bulk2DeleteJob, bulk2GetSuccessfulResults,
-     * bulk2GetFailedResults, bulk2GetUnprocessedRecords, bulk2CreateQueryJob,
-     * bulk2GetQueryJob, bulk2GetAllQueryJobs, bulk2GetQueryJobResults,
-     * bulk2AbortQueryJob, bulk2DeleteQueryJob
+     * composite-tree, composite-batch, composite,
+     * compositeRetrieveSObjectCollections, compositeCreateSObjectCollections,
+     * compositeUpdateSObjectCollections, compositeUpsertSObjectCollections,
+     * compositeDeleteSObjectCollections, bulk2GetAllJobs, bulk2CreateJob,
+     * bulk2GetJob, bulk2CreateBatch, bulk2CloseJob, bulk2AbortJob,
+     * bulk2DeleteJob, bulk2GetSuccessfulResults, bulk2GetFailedResults,
+     * bulk2GetUnprocessedRecords, bulk2CreateQueryJob, bulk2GetQueryJob,
+     * bulk2GetAllQueryJobs, bulk2GetQueryJobResults, bulk2AbortQueryJob,
+     * bulk2DeleteQueryJob
      * 
      * Path parameter: topicName
      * The name of the topic/channel to use
diff --git a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SalesforceEndpointBuilderFactory.java b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SalesforceEndpointBuilderFactory.java
index 4a81141..ed5654c 100644
--- a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SalesforceEndpointBuilderFactory.java
+++ b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SalesforceEndpointBuilderFactory.java
@@ -2285,6 +2285,39 @@ public interface SalesforceEndpointBuilderFactory {
             return this;
         }
         /**
+         * Composite API option to indicate to rollback all records if any are
+         * not successful.
+         * 
+         * The option is a: &lt;code&gt;boolean&lt;/code&gt; type.
+         * 
+         * Default: false
+         * Group: producer
+         * 
+         * @param allOrNone the value to set
+         * @return the dsl builder
+         */
+        default SalesforceEndpointProducerBuilder allOrNone(boolean allOrNone) {
+            doSetProperty("allOrNone", allOrNone);
+            return this;
+        }
+        /**
+         * Composite API option to indicate to rollback all records if any are
+         * not successful.
+         * 
+         * The option will be converted to a &lt;code&gt;boolean&lt;/code&gt;
+         * type.
+         * 
+         * Default: false
+         * Group: producer
+         * 
+         * @param allOrNone the value to set
+         * @return the dsl builder
+         */
+        default SalesforceEndpointProducerBuilder allOrNone(String allOrNone) {
+            doSetProperty("allOrNone", allOrNone);
+            return this;
+        }
+        /**
          * APEX method URL.
          * 
          * The option is a: &lt;code&gt;java.lang.String&lt;/code&gt; type.
@@ -3485,7 +3518,7 @@ public interface SalesforceEndpointBuilderFactory {
          * 
          * Path parameter: operationName
          * The operation to use
-         * There are 59 enums and the value can be one of: getVersions,
+         * There are 64 enums and the value can be one of: getVersions,
          * getResources, getGlobalObjects, getBasicInfo, getDescription,
          * getSObject, createSObject, updateSObject, deleteSObject,
          * getSObjectWithId, upsertSObject, deleteSObjectWithId, getBlobField,
@@ -3495,9 +3528,12 @@ public interface SalesforceEndpointBuilderFactory {
          * getQueryResult, getRecentReports, getReportDescription,
          * executeSyncReport, executeAsyncReport, getReportInstances,
          * getReportResults, limits, approval, approvals, composite-tree,
-         * composite-batch, composite, bulk2GetAllJobs, bulk2CreateJob,
-         * bulk2GetJob, bulk2CreateBatch, bulk2CloseJob, bulk2AbortJob,
-         * bulk2DeleteJob, bulk2GetSuccessfulResults, bulk2GetFailedResults,
+         * composite-batch, composite, compositeRetrieveSObjectCollections,
+         * compositeCreateSObjectCollections, compositeUpdateSObjectCollections,
+         * compositeUpsertSObjectCollections, compositeDeleteSObjectCollections,
+         * bulk2GetAllJobs, bulk2CreateJob, bulk2GetJob, bulk2CreateBatch,
+         * bulk2CloseJob, bulk2AbortJob, bulk2DeleteJob,
+         * bulk2GetSuccessfulResults, bulk2GetFailedResults,
          * bulk2GetUnprocessedRecords, bulk2CreateQueryJob, bulk2GetQueryJob,
          * bulk2GetAllQueryJobs, bulk2GetQueryJobResults, bulk2AbortQueryJob,
          * bulk2DeleteQueryJob
@@ -3523,7 +3559,7 @@ public interface SalesforceEndpointBuilderFactory {
          * 
          * Path parameter: operationName
          * The operation to use
-         * There are 59 enums and the value can be one of: getVersions,
+         * There are 64 enums and the value can be one of: getVersions,
          * getResources, getGlobalObjects, getBasicInfo, getDescription,
          * getSObject, createSObject, updateSObject, deleteSObject,
          * getSObjectWithId, upsertSObject, deleteSObjectWithId, getBlobField,
@@ -3533,9 +3569,12 @@ public interface SalesforceEndpointBuilderFactory {
          * getQueryResult, getRecentReports, getReportDescription,
          * executeSyncReport, executeAsyncReport, getReportInstances,
          * getReportResults, limits, approval, approvals, composite-tree,
-         * composite-batch, composite, bulk2GetAllJobs, bulk2CreateJob,
-         * bulk2GetJob, bulk2CreateBatch, bulk2CloseJob, bulk2AbortJob,
-         * bulk2DeleteJob, bulk2GetSuccessfulResults, bulk2GetFailedResults,
+         * composite-batch, composite, compositeRetrieveSObjectCollections,
+         * compositeCreateSObjectCollections, compositeUpdateSObjectCollections,
+         * compositeUpsertSObjectCollections, compositeDeleteSObjectCollections,
+         * bulk2GetAllJobs, bulk2CreateJob, bulk2GetJob, bulk2CreateBatch,
+         * bulk2CloseJob, bulk2AbortJob, bulk2DeleteJob,
+         * bulk2GetSuccessfulResults, bulk2GetFailedResults,
          * bulk2GetUnprocessedRecords, bulk2CreateQueryJob, bulk2GetQueryJob,
          * bulk2GetAllQueryJobs, bulk2GetQueryJobResults, bulk2AbortQueryJob,
          * bulk2DeleteQueryJob
diff --git a/docs/components/modules/ROOT/pages/salesforce-component.adoc b/docs/components/modules/ROOT/pages/salesforce-component.adoc
index 79a59f6..5e951df 100644
--- a/docs/components/modules/ROOT/pages/salesforce-component.adoc
+++ b/docs/components/modules/ROOT/pages/salesforce-component.adoc
@@ -160,7 +160,14 @@ results) using result link returned from the 'query' API
 * composite - submit up to 25 possibly related REST requests and receive individual responses. It's also possible to use "raw" composite without limitation.
 * composite-tree - create up to 200 records with parent-child relationships (up to 5 levels) in one go
 * composite-batch - submit a composition of requests in batch
-* queryAll - Runs a SOQL query. It returns the results that are deleted because of a merge or delete. Also returns the  information about archived Task and Event records.
+* compositeRetrieveSObjectCollections - Retrieve one or more records of the same object type.
+* compositeCreateSObjectCollections - Add up to 200 records, returning a list of SaveSObjectResult objects.
+* compositeUpdateSObjectCollections - Update up to 200 records, returning a list of SaveSObjectResult objects.
+* compositeUpsertSObjectCollections - Create or update (upsert) up to 200 records based on an external ID field.
+Returns a list of UpsertSObjectResult objects.
+* compositeDeleteSObjectCollections - Delete up to 200 records, returning a list of SaveSObjectResult objects.
+* queryAll - Runs a SOQL query. It returns the results that are deleted because of a merge or delete. Also returns
+the  information about archived Task and Event records.
 * getBlobField - Retrieves the specified blob field from an individual record.
 * apexCall - Executes a user defined APEX REST API call.
 
@@ -669,6 +676,60 @@ With this approach, you have the complete control on the Salesforce request.
 `compositeMethod` option to override to the other supported value, `GET`, which returns a list of
 other available composite resources.
 
+== Using Composite SObject Collections
+
+The SObject Collections API executes actions on multiple records in one request. Use sObject Collections to reduce the number of round-trips between the client and server. The entire request counts as a single call toward your API limits. This resource is available in API version 42.0 and later. `SObject` records (aka DTOs) supplied to these operations must be instances of subclasses of `AbstractDescribedSObjectBase`. See the Maven Plugin section for information on generating these DTO c [...]
+
+=== compositeRetrieveSObjectCollections
+Retrieve one or more records of the same object type.
+|===
+| Parameter | Type | Description | Default | Required
+
+| ids | List of String or comma-separated string | A list of one or more IDs of the objects to return. All IDs must belong to the same object type. | | x
+| fields | List of String or comma-separated string | A list of fields to include in the response. The field names you specify must be valid, and you must have read-level permissions to each field. | | x
+| sObjectName | String | Type of SObject, e.g. `Account` | | x
+| sObjectClass | String | Fully-qualified class name of DTO class to use for deserializing the response. | | Required if `sObjectName` parameter does not resolve to a class that exists in the package specified by the `package` option.
+|===
+
+=== compositeCreateSObjectCollections
+Add up to 200 records, returning a list of SaveSObjectResult objects. Mixed SObject types is supported.
+|===
+| Parameter | Type | Description| Default| Required
+
+| request body | List of `SObject` | A list of SObjects to create | | x
+| allOrNone | boolean | Indicates whether to roll back the entire request when the creation of any object fails (true) or to continue with the independent creation of other objects in the request. | false |
+|===
+
+=== compositeUpdateSObjectCollections
+Update up to 200 records, returning a list of SaveSObjectResult objects. Mixed SObject types is supported.
+|===
+| Parameter | Type | Description | Default | Required
+
+| request body | List of `SObject` | A list of SObjects to update | | x
+| allOrNone | boolean | Indicates whether to roll back the entire request when the update of any object fails (true) or to continue with the independent update of other objects in the request. | false |
+|===
+
+=== compositeUpsertSObjectCollections
+Create or update (upsert) up to 200 records based on an external ID field, returning a list of UpsertSObjectResult
+objects. Mixed SObject types is not supported.
+|===
+| Parameter | Type | Description | Default | Required
+
+| request body | List of `SObject` | A list of SObjects to upsert | | x
+| allOrNone | boolean |  Indicates whether to roll back the entire request when the upsert of any object fails (true) or to continue with the independent upsert of other objects in the request. | false |
+| sObjectName | String | Type of SObject, e.g. `Account` | | x
+| sObjectIdName | String | Name of External ID field | | x
+|===
+
+=== compositeDeleteSObjectCollections
+Delete up to 200 records, returning a list of DeleteSObjectResult objects. Mixed SObject types is supported.
+|===
+| Parameter | Type | Description | Default | Required
+
+| ids | List of String or comma-separated string | A list of up to 200 IDs of objects to be deleted. | | x
+| allOrNone | boolean | Indicates whether to roll back the entire request when the upsert of any object fails (true) or to continue with the independent upsert of other objects in the request. | false |
+|===
+
 
 ==  Sending null values to salesforce
 
@@ -717,14 +778,8 @@ for details on how to generate the DTO.
 
 == Options
 
-
-
-
-
-
-
 // component options: START
-The Salesforce component supports 79 options, which are listed below.
+The Salesforce component supports 80 options, which are listed below.
 
 
 
@@ -782,6 +837,7 @@ The Salesforce component supports 79 options, which are listed below.
 | *httpClientProperties* (common) | Used to set any properties that can be configured on the underlying HTTP client. Have a look at properties of SalesforceHttpClient and the Jetty HttpClient for all available options. |  | Map
 | *longPollingTransportProperties* (common) | Used to set any properties that can be configured on the LongPollingTransport used by the BayeuxClient (CometD) used by the streaming api |  | Map
 | *bridgeErrorHandler* (consumer) | Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored. | false | boolean
+| *allOrNone* (producer) | Composite API option to indicate to rollback all records if any are not successful. | false | boolean
 | *apexUrl* (producer) | APEX method URL |  | String
 | *compositeMethod* (producer) | Composite (raw) method. |  | String
 | *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...]
@@ -837,12 +893,12 @@ with the following path and query parameters:
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
 | Name | Description | Default | Type
-| *operationName* | The operation to use. There are 59 enums and the value can be one of: getVersions, getResources, getGlobalObjects, getBasicInfo, getDescription, getSObject, createSObject, updateSObject, deleteSObject, getSObjectWithId, upsertSObject, deleteSObjectWithId, getBlobField, query, queryMore, queryAll, search, apexCall, recent, createJob, getJob, closeJob, abortJob, createBatch, getBatch, getAllBatches, getRequest, getResults, createBatchQuery, getQueryResultIds, getQueryRe [...]
+| *operationName* | The operation to use. There are 64 enums and the value can be one of: getVersions, getResources, getGlobalObjects, getBasicInfo, getDescription, getSObject, createSObject, updateSObject, deleteSObject, getSObjectWithId, upsertSObject, deleteSObjectWithId, getBlobField, query, queryMore, queryAll, search, apexCall, recent, createJob, getJob, closeJob, abortJob, createBatch, getBatch, getAllBatches, getRequest, getResults, createBatchQuery, getQueryResultIds, getQueryRe [...]
 | *topicName* | The name of the topic/channel to use |  | String
 |===
 
 
-=== Query Parameters (49 parameters):
+=== Query Parameters (50 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -894,6 +950,7 @@ with the following path and query parameters:
 | *replayId* (consumer) | The replayId value to use when subscribing |  | Long
 | *exceptionHandler* (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By default the consumer will deal with exceptions, that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
 | *exchangePattern* (consumer) | Sets the exchange pattern when the consumer creates an exchange. There are 3 enums and the value can be one of: InOnly, InOut, InOptionalOut |  | ExchangePattern
+| *allOrNone* (producer) | Composite API option to indicate to rollback all records if any are not successful. | false | boolean
 | *apexUrl* (producer) | APEX method URL |  | String
 | *compositeMethod* (producer) | Composite (raw) method. |  | String
 | *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...]