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 2025/07/30 19:57:20 UTC
(camel) branch main updated: CAMEL-22244: camel-salesforce: Add support for multipart SObject creation with binary field detection
This is an automated email from the ASF dual-hosted git repository.
jeremyross pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 3711604973d CAMEL-22244: camel-salesforce: Add support for multipart SObject creation with binary field detection
3711604973d is described below
commit 3711604973d76254310e4837fb4ac50ae9358329
Author: Jeremy Ross <je...@gmail.com>
AuthorDate: Sun Jul 27 13:20:08 2025 -0500
CAMEL-22244: camel-salesforce: Add support for multipart SObject creation with binary field detection
---
.../src/main/resources/sobject-pojo.vm | 33 +++-
.../src/main/docs/salesforce-component.adoc | 157 +++++++++++++++-
.../internal/client/DefaultRestClient.java | 201 ++++++++++++++++++++
.../salesforce/internal/client/RestClient.java | 27 +++
.../internal/processor/AbstractRestProcessor.java | 72 +++++++-
.../component/salesforce/RestApiManualIT.java | 48 ++++-
.../salesforce/dto/generated/ContentVersion.java | 47 +++--
.../salesforce/dto/generated/Document.java | 98 ++++++++--
.../component/salesforce/dto/generated/Folder.java | 202 +++++++++++++++++++++
.../dto/generated/QueryRecordsFolder.java | 30 +++
10 files changed, 867 insertions(+), 48 deletions(-)
diff --git a/components/camel-salesforce/camel-salesforce-codegen/src/main/resources/sobject-pojo.vm b/components/camel-salesforce/camel-salesforce-codegen/src/main/resources/sobject-pojo.vm
index 80cf5761165..5a7c1a38391 100644
--- a/components/camel-salesforce/camel-salesforce-codegen/src/main/resources/sobject-pojo.vm
+++ b/components/camel-salesforce/camel-salesforce-codegen/src/main/resources/sobject-pojo.vm
@@ -23,10 +23,20 @@ package $packageName;
import java.util.ArrayList;
import java.util.List;
-import jakarta.annotation.Generated;
-
#set ( $hasPicklists = $utility.hasPicklists($desc) )
#set ( $hasMultiSelectPicklists = $utility.hasMultiSelectPicklists($desc) )
+#set ( $hasBlobFields = false )
+#foreach ( $field in $desc.Fields )
+#if ( $utility.isBlobField($field) )
+#set ( $hasBlobFields = true )
+#break
+#end
+#end
+#if ( $hasBlobFields )
+import java.io.InputStream;
+#end
+import jakarta.annotation.Generated;
+
#if ( $hasPicklists && !$useStringsForPicklists )
#end
#if ( $hasMultiSelectPicklists )
@@ -52,6 +62,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.annotation.JsonTypeResolver;
+#if ( $hasBlobFields )
+import com.fasterxml.jackson.annotation.JsonIgnore;
+#end
import org.apache.camel.component.salesforce.api.utils.AsNestedPropertyResolver;
#if ( $hasMultiSelectPicklists )
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@@ -77,6 +90,7 @@ public class $desc.Name extends AbstractDescribedSObjectBase {
#if ( ($utility.notBaseField($field.Name)) && ($fieldType) )
#set ( $fieldName = $field.Name )
#set ( $isMultiSelectPicklist = $utility.isMultiSelectPicklist($field) )
+#set ( $isBlobField = $utility.isBlobField($field) )
#set ( $propertyName = $fieldName )
private $fieldType $propertyName;
@@ -104,6 +118,21 @@ public class $desc.Name extends AbstractDescribedSObjectBase {
this.$propertyName = $propertyName;
}
+#if ( $isBlobField )
+ @JsonIgnore
+ private InputStream ${propertyName}Binary;
+
+ @JsonIgnore
+ public InputStream get${propertyName}Binary() {
+ return this.${propertyName}Binary;
+ }
+
+ @JsonIgnore
+ public void set${propertyName}Binary(InputStream ${propertyName}Binary) {
+ this.${propertyName}Binary = ${propertyName}Binary;
+ }
+
+#end
#end
#if ( $field.type == "reference" && $utility.notNull($field.relationshipName) )## IS LOOKUP $hasDescription
#if ( $field.getReferenceTo().size() > 1 )
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 b9c50e3a38f..be5b55bd808 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
@@ -457,6 +457,10 @@ Creates a record in salesforce.
Type: `CreateSObjectResult`
+*Multipart Support*
+
+When creating records with blob/binary fields, you can use the automatic https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_sobject_insert_update_blob.htm[multipart encoding] feature by populating binary fields in your DTO. See <<BinaryFields,Binary Fields and Multipart Requests>> for details.
+
[[updateSObject]]
===== Update SObject
@@ -472,6 +476,10 @@ Updates a record in salesforce.
| `sObjectId` | `String` | Id of record to update. Only used if Camel cannot determine from Body. | | If Body is a `String`
|===
+*Multipart Support*
+
+When updating records with blob/binary fields, you can use the automatic https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_sobject_insert_update_blob.htm[multipart encoding] feature by populating binary fields in your DTO. See <<BinaryFields,Binary Fields and Multipart Requests>> for details.
+
[[upsertSObject]]
===== Upsert SObject
@@ -1020,6 +1028,109 @@ Gets the definition of a Platform Event in JSON format. Other types of events su
Type: `InputStream`
+[[BinaryFields]]
+==== Binary Fields and Multipart Requests
+
+The Salesforce component provides automatic support for handling binary fields (blob fields) in SObjects without requiring manual base64 encoding. This feature works with both `createSObject` and `updateSObject` operations.
+
+===== Binary Field Pattern
+
+For any SObject with blob fields, you can use binary fields that follow the naming pattern `pass:[***]Binary`, where `pass:[***]` is the original field name. For example:
+
+* `VersionData` field → `VersionDataBinary` field
+* `Body` field → `BodyBinary` field
+* `ContentData` field → `ContentDataBinary` field
+
+===== Automatic Multipart Detection
+
+When you populate a `pass:[***]Binary` field with an `InputStream`, the component automatically detects this and switches to multipart encoding for the request. This means that the binary data is sent directly as a stream, avoiding the overhead of base64 encoding.:
+
+===== Usage Examples
+
+*Creating a ContentVersion with binary data:*
+
+[source,java]
+----
+// Create ContentVersion with binary field
+ContentVersion cv = new ContentVersion();
+cv.setTitle("My Document");
+cv.setPathOnClient("document.pdf");
+
+// Use binary field instead of base64 encoded string
+InputStream fileData = new FileInputStream("document.pdf");
+cv.setVersionDataBinary(fileData); // Automatically triggers multipart request
+
+// Send to Salesforce
+template.requestBody("salesforce:createSObject", cv);
+----
+
+*Updating a Document with binary content:*
+
+[source,java]
+----
+// Update Document with binary field
+Document doc = new Document();
+doc.setId("01234567890123456");
+doc.setName("Updated Document");
+
+// Use binary field for efficient upload
+InputStream content = getClass().getResourceAsStream("/updated-content.pdf");
+doc.setBodyBinary(content); // Automatically triggers multipart request
+
+// Send to Salesforce
+template.requestBody("salesforce:updateSObject", doc);
+----
+
+===== DTO Generation
+
+When using the <<MavenPlugin,Camel Salesforce Maven Plugin>>, binary fields are automatically generated for blob fields:
+
+[source,java]
+----
+public class ContentVersion extends AbstractSObjectBase {
+
+ // Standard base64 field (for backward compatibility)
+ private String VersionData;
+
+ // Generated binary field (new efficient approach)
+ @JsonIgnore
+ private InputStream VersionDataBinary;
+
+ // Getters and setters for both fields...
+}
+----
+
+===== Field Priority
+
+When both the standard field and binary field are populated:
+
+* **Binary field takes precedence** - The `pass:[***]Binary` field is used and a multipart request is made
+* **Standard field is ignored** - The base64 string field is not sent in the multipart request
+* **Automatic cleanup** - Binary field names are automatically removed from the JSON payload
+
+===== Performance Benefits
+
+Using binary fields provides significant performance improvements:
+
+* **No base64 encoding** required on the client side
+* **Direct streaming** of binary data to Salesforce
+* **Reduced memory usage** for large files
+* **Faster upload times** especially for large documents
+* **Higher salesforce limits** for multipart requests compared to base64 strings. Salesforce limits base64 strings to 50 MB of text data or 37.5 MB of base64–encoded data. Multipart uploads can handle 2 GB for ContentVersion records, and 500 MB for all other objects.
+
+===== Backward Compatibility
+
+The existing base64 string approach continues to work:
+
+[source,java]
+----
+// Still supported - base64 approach
+ContentVersion cv = new ContentVersion();
+cv.setVersionData(base64EncodedString); // Uses standard JSON request
+----
+
+However, using binary fields is recommended for better performance when working with binary data.
+
[[ApexRESTAPI]]
==== Apex REST API
@@ -2034,7 +2145,9 @@ The response is:
=== Uploading a document to a ContentWorkspace
-Create the ContentVersion in Java, using a Processor instance:
+==== Using Binary Fields (Recommended)
+
+For efficient document uploads without base64 encoding overhead, use the binary field approach:
[source,java]
----
@@ -2047,10 +2160,10 @@ public class ContentProcessor implements Processor {
cv.setFirstPublishLocationId(cw.getId());
cv.setTitle("test document");
cv.setPathOnClient("test_doc.html");
- byte[] document = message.getBody(byte[].class);
- ObjectMapper mapper = new ObjectMapper();
- String enc = mapper.convertValue(document, String.class);
- cv.setVersionDataUrl(enc);
+
+ // Use binary field for efficient upload - no base64 encoding needed
+ InputStream document = message.getBody(InputStream.class);
+ cv.setVersionDataBinary(document); // Automatically triggers multipart request
message.setBody(cv);
}
@@ -2067,11 +2180,41 @@ Give the output from the processor to the Salesforce component:
[source,java]
----
from("file:///home/camel/library")
- .to(new ContentProcessor()) // convert bytes from the file into a ContentVersion SObject
- // for the salesforce component
+ .to(new ContentProcessor()) // convert file stream into a ContentVersion SObject
+ // with binary field for efficient upload
.to("salesforce:createSObject");
----
+==== Using Base64 Encoding (Legacy)
+
+The traditional base64 encoding approach is still supported for backward compatibility:
+
+[source,java]
+----
+public class ContentProcessor implements Processor {
+ public void process(Exchange exchange) throws Exception {
+ Message message = exchange.getIn();
+
+ ContentVersion cv = new ContentVersion();
+ ContentWorkspace cw = getWorkspace(exchange);
+ cv.setFirstPublishLocationId(cw.getId());
+ cv.setTitle("test document");
+ cv.setPathOnClient("test_doc.html");
+ byte[] document = message.getBody(byte[].class);
+ ObjectMapper mapper = new ObjectMapper();
+ String enc = mapper.convertValue(document, String.class);
+ cv.setVersionData(enc); // Uses base64 encoding and standard JSON request
+ message.setBody(cv);
+ }
+
+ protected ContentWorkspace getWorkSpace(Exchange exchange) {
+ // Look up the content workspace somehow, maybe use enrich() to add it to a
+ // header that can be extracted here
+ ....
+ }
+}
+----
+
=== Generating SOQL query strings
`org.apache.camel.component.salesforce.api.utils.QueryHelper` contains helper
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultRestClient.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultRestClient.java
index c88de491804..654b9ab88d7 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultRestClient.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultRestClient.java
@@ -16,16 +16,22 @@
*/
package org.apache.camel.component.salesforce.internal.client;
+import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.camel.component.salesforce.SalesforceHttpClient;
import org.apache.camel.component.salesforce.SalesforceLoginConfig;
import org.apache.camel.component.salesforce.api.SalesforceException;
@@ -34,9 +40,12 @@ import org.apache.camel.component.salesforce.internal.SalesforceSession;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.URISupport;
import org.eclipse.jetty.client.InputStreamRequestContent;
+import org.eclipse.jetty.client.MultiPartRequestContent;
import org.eclipse.jetty.client.Request;
+import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.MultiPart;
public class DefaultRestClient extends AbstractClientBase implements RestClient {
@@ -169,6 +178,127 @@ public class DefaultRestClient extends AbstractClientBase implements RestClient
doHttpRequest(post, new DelegatingClientCallback(callback));
}
+ @Override
+ public void createSObjectMultipart(
+ String sObjectName, Object sObjectDto, InputStream sObject,
+ Map<String, List<String>> headers, ResponseCallback callback) {
+ try {
+ final Request post = getRequest(HttpMethod.POST, sobjectsUrl(sObjectName), headers);
+
+ setAccessToken(post);
+
+ MultiPartRequestContent multipartContent = new MultiPartRequestContent();
+
+ ObjectMapper objectMapper = new ObjectMapper();
+ JsonNode jsonNode = objectMapper.readTree(sObject);
+
+ if (jsonNode.isObject()) {
+ ObjectNode objectNode = (ObjectNode) jsonNode;
+ ObjectNode cleanJson = objectNode.deepCopy();
+
+ Map<String, InputStream> binaryFields = getBinaryFieldMap(sObjectDto);
+
+ if (!binaryFields.isEmpty()) {
+
+ // Remove binary field names from JSON first
+ for (String fieldName : binaryFields.keySet()) {
+ cleanJson.remove(fieldName);
+ }
+
+ // non-binary json data must be the first part of the multipart request
+ String cleanJsonString = objectMapper.writeValueAsString(cleanJson);
+ multipartContent.addPart(new MultiPart.ContentSourcePart(
+ "entity", null,
+ HttpFields.build().add(HttpHeader.CONTENT_TYPE, APPLICATION_JSON_UTF8),
+ new InputStreamRequestContent(
+ new ByteArrayInputStream(cleanJsonString.getBytes(StandardCharsets.UTF_8)))));
+
+ // Then add binary fields as subsequent parts
+ for (Map.Entry<String, InputStream> entry : binaryFields.entrySet()) {
+ String fieldName = entry.getKey();
+ InputStream binaryData = entry.getValue();
+
+ String contentType = inferContentType(fieldName, sObjectName);
+ multipartContent.addPart(new MultiPart.ContentSourcePart(
+ fieldName, "temp-file-name.doc",
+ HttpFields.build().add(HttpHeader.CONTENT_TYPE, contentType),
+ new InputStreamRequestContent(binaryData)));
+ }
+ } else {
+ // No multipart data found - this shouldn't happen as processor should handle this case
+ callback.onResponse(null, Collections.emptyMap(),
+ new SalesforceException("createSObjectMultipart called but no binary fields found", null));
+ return;
+ }
+ } else {
+ // If not a JSON object, send as-is
+ multipartContent.addPart(new MultiPart.ContentSourcePart(
+ "entity", null,
+ HttpFields.build().add(HttpHeader.CONTENT_TYPE, APPLICATION_JSON_UTF8),
+ new InputStreamRequestContent(sObject)));
+ }
+
+ multipartContent.close();
+ post.body(multipartContent);
+
+ doHttpRequest(post, new DelegatingClientCallback(callback));
+ } catch (Exception e) {
+ // If JSON parsing fails, fall back to regular processing
+ callback.onResponse(null, Collections.emptyMap(),
+ new SalesforceException("Failed to process multipart request: " + e.getMessage(), e));
+ }
+ }
+
+ private Map<String, InputStream> getBinaryFieldMap(Object sObject) {
+ Map<String, InputStream> binaryFields = new HashMap<>();
+
+ if (sObject == null) {
+ return binaryFields;
+ }
+
+ Class<?> clazz = sObject.getClass();
+ java.lang.reflect.Field[] fields = clazz.getDeclaredFields();
+
+ for (java.lang.reflect.Field field : fields) {
+ String fieldName = field.getName();
+
+ if (fieldName.endsWith("Binary") && field.isAnnotationPresent(JsonIgnore.class)) {
+ try {
+ field.setAccessible(true);
+ Object value = field.get(sObject);
+ if (value instanceof InputStream) {
+ String originalFieldName = fieldName.replace("Binary", "");
+ binaryFields.put(originalFieldName, (InputStream) value);
+ }
+ } catch (Exception e) {
+ // Skip inaccessible fields
+ }
+ }
+ }
+
+ return binaryFields;
+ }
+
+ private String inferContentType(String fieldName, String sObjectType) {
+ // Infer content type based on field name and object type
+ switch (fieldName.toLowerCase()) {
+ case "body":
+ if ("Document".equalsIgnoreCase(sObjectType)) {
+ return "application/octet-stream";
+ } else if ("Attachment".equalsIgnoreCase(sObjectType)) {
+ return "application/octet-stream";
+ }
+ break;
+ case "versiondata":
+ return "application/octet-stream";
+ case "contentdata":
+ return "application/octet-stream";
+ default:
+ return "application/octet-stream";
+ }
+ return "application/octet-stream";
+ }
+
@Override
public void updateSObject(
String sObjectName, String id, InputStream sObject, Map<String, List<String>> headers, ResponseCallback callback) {
@@ -183,6 +313,77 @@ public class DefaultRestClient extends AbstractClientBase implements RestClient
doHttpRequest(patch, new DelegatingClientCallback(callback));
}
+ @Override
+ public void updateSObjectMultipart(
+ String sObjectName, String id, Object sObjectDto, InputStream sObject,
+ Map<String, List<String>> headers, ResponseCallback callback) {
+ try {
+ final Request patch = getRequest("PATCH", sobjectsUrl(sObjectName + "/" + id), headers);
+
+ setAccessToken(patch);
+
+ MultiPartRequestContent multipartContent = new MultiPartRequestContent();
+
+ ObjectMapper objectMapper = new ObjectMapper();
+ JsonNode jsonNode = objectMapper.readTree(sObject);
+
+ if (jsonNode.isObject()) {
+ ObjectNode objectNode = (ObjectNode) jsonNode;
+ ObjectNode cleanJson = objectNode.deepCopy();
+
+ Map<String, InputStream> binaryFields = getBinaryFieldMap(sObjectDto);
+
+ if (!binaryFields.isEmpty()) {
+
+ // Remove binary field names from JSON first
+ for (String fieldName : binaryFields.keySet()) {
+ cleanJson.remove(fieldName);
+ }
+
+ // non-binary json data must be the first part of the multipart request
+ String cleanJsonString = objectMapper.writeValueAsString(cleanJson);
+ multipartContent.addPart(new MultiPart.ContentSourcePart(
+ "entity", null,
+ HttpFields.build().add(HttpHeader.CONTENT_TYPE, APPLICATION_JSON_UTF8),
+ new InputStreamRequestContent(
+ new ByteArrayInputStream(cleanJsonString.getBytes(StandardCharsets.UTF_8)))));
+
+ // Then add binary fields as subsequent parts
+ for (Map.Entry<String, InputStream> entry : binaryFields.entrySet()) {
+ String fieldName = entry.getKey();
+ InputStream binaryData = entry.getValue();
+
+ String contentType = inferContentType(fieldName, sObjectName);
+ multipartContent.addPart(new MultiPart.ContentSourcePart(
+ fieldName, "temp-file-name.doc",
+ HttpFields.build().add(HttpHeader.CONTENT_TYPE, contentType),
+ new InputStreamRequestContent(binaryData)));
+ }
+ } else {
+ // No multipart data found - this shouldn't happen as processor should handle this case
+ callback.onResponse(null, Collections.emptyMap(),
+ new SalesforceException("updateSObjectMultipart called but no binary fields found", null));
+ return;
+ }
+ } else {
+ // If not a JSON object, send as-is
+ multipartContent.addPart(new MultiPart.ContentSourcePart(
+ "entity", null,
+ HttpFields.build().add(HttpHeader.CONTENT_TYPE, APPLICATION_JSON_UTF8),
+ new InputStreamRequestContent(sObject)));
+ }
+
+ multipartContent.close();
+ patch.body(multipartContent);
+
+ doHttpRequest(patch, new DelegatingClientCallback(callback));
+ } catch (Exception e) {
+ // If JSON parsing fails, fall back to regular processing
+ callback.onResponse(null, Collections.emptyMap(),
+ new SalesforceException("Failed to process multipart update request: " + e.getMessage(), e));
+ }
+ }
+
@Override
public void deleteSObject(String sObjectName, String id, Map<String, List<String>> headers, ResponseCallback callback) {
final Request delete = getRequest(HttpMethod.DELETE, sobjectsUrl(sObjectName + "/" + id), headers);
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java
index c8bf525ff1a..4d67b25f5d0 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java
@@ -92,6 +92,19 @@ public interface RestClient {
*/
void createSObject(String sObjectName, InputStream sObject, Map<String, List<String>> headers, ResponseCallback callback);
+ /**
+ * Creates multipart SObject using multipart/form-data for blob fields, with automatic binary field detection.
+ *
+ * @param sObjectName specified object name
+ * @param sObjectDto original DTO object for binary field detection (AbstractSObjectBase or subclass)
+ * @param sObject request entity as JSON
+ * @param headers additional HTTP headers to send
+ * @param callback {@link ResponseCallback} to handle response or exception
+ */
+ void createSObjectMultipart(
+ String sObjectName, Object sObjectDto, InputStream sObject,
+ Map<String, List<String>> headers, ResponseCallback callback);
+
/**
* Updates a record for the specified object ID.
*
@@ -104,6 +117,20 @@ public interface RestClient {
void updateSObject(
String sObjectName, String id, InputStream sObject, Map<String, List<String>> headers, ResponseCallback callback);
+ /**
+ * Updates multipart SObject using multipart/form-data for blob fields, with automatic binary field detection.
+ *
+ * @param sObjectName specified object name
+ * @param id object id
+ * @param sObjectDto original DTO object for binary field detection (AbstractSObjectBase or subclass)
+ * @param sObject request entity as JSON
+ * @param headers additional HTTP headers to send
+ * @param callback {@link ResponseCallback} to handle response or exception
+ */
+ void updateSObjectMultipart(
+ String sObjectName, String id, Object sObjectDto, InputStream sObject,
+ Map<String, List<String>> headers, ResponseCallback callback);
+
/**
* Deletes a record for the specified object ID.
*
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 724386879a2..254ade8f7da 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
@@ -30,6 +30,7 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import org.apache.camel.AsyncCallback;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
@@ -378,8 +379,44 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor
private void processCreateSobject(final Exchange exchange, final AsyncCallback callback) throws SalesforceException {
String sObjectName = determineSObjectName(exchange);
- restClient.createSObject(sObjectName, getRequestStream(exchange), determineHeaders(exchange),
- processWithResponseCallback(exchange, callback));
+ Message in = exchange.getIn();
+ AbstractSObjectBase sObjectBase = in.getBody(AbstractSObjectBase.class);
+
+ if (sObjectBase != null && detectBinaryFields(sObjectBase)) {
+ restClient.createSObjectMultipart(sObjectName, sObjectBase, getRequestStream(exchange),
+ determineHeaders(exchange),
+ processWithResponseCallback(exchange, callback));
+ } else {
+ restClient.createSObject(sObjectName, getRequestStream(exchange), determineHeaders(exchange),
+ processWithResponseCallback(exchange, callback));
+ }
+ }
+
+ private boolean detectBinaryFields(AbstractSObjectBase sObject) {
+ if (sObject == null) {
+ return false;
+ }
+
+ Class<?> clazz = sObject.getClass();
+ java.lang.reflect.Field[] fields = clazz.getDeclaredFields();
+
+ for (java.lang.reflect.Field field : fields) {
+ String fieldName = field.getName();
+
+ if (fieldName.endsWith("Binary") && field.isAnnotationPresent(JsonIgnore.class)) {
+ try {
+ field.setAccessible(true);
+ Object value = field.get(sObject);
+ if (value instanceof InputStream) {
+ return true;
+ }
+ } catch (Exception e) {
+ // Skip inaccessible fields
+ }
+ }
+ }
+
+ return false;
}
private void processUpdateSobject(final Exchange exchange, final AsyncCallback callback) throws SalesforceException {
@@ -393,14 +430,29 @@ public abstract class AbstractRestProcessor extends AbstractSalesforceProcessor
}
final String finalsObjectId = sObjectId;
- restClient.updateSObject(sObjectName, sObjectId, getRequestStream(exchange), determineHeaders(exchange),
- new RestClient.ResponseCallback() {
- @Override
- public void onResponse(InputStream response, Map<String, String> headers, SalesforceException exception) {
- restoreFields(exchange, sObjectBase, finalsObjectId, null, null);
- processResponse(exchange, response, headers, exception, callback);
- }
- });
+
+ if (sObjectBase != null && detectBinaryFields(sObjectBase)) {
+ restClient.updateSObjectMultipart(sObjectName, sObjectId, sObjectBase, getRequestStream(exchange),
+ determineHeaders(exchange),
+ new RestClient.ResponseCallback() {
+ @Override
+ public void onResponse(
+ InputStream response, Map<String, String> headers, SalesforceException exception) {
+ restoreFields(exchange, sObjectBase, finalsObjectId, null, null);
+ processResponse(exchange, response, headers, exception, callback);
+ }
+ });
+ } else {
+ restClient.updateSObject(sObjectName, sObjectId, getRequestStream(exchange), determineHeaders(exchange),
+ new RestClient.ResponseCallback() {
+ @Override
+ public void onResponse(
+ InputStream response, Map<String, String> headers, SalesforceException exception) {
+ restoreFields(exchange, sObjectBase, finalsObjectId, null, null);
+ processResponse(exchange, response, headers, exception, callback);
+ }
+ });
+ }
}
private void processDeleteSobject(final Exchange exchange, final AsyncCallback callback) throws SalesforceException {
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiManualIT.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiManualIT.java
index 0866db4fae6..783784e1319 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiManualIT.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiManualIT.java
@@ -51,10 +51,12 @@ import org.apache.camel.component.salesforce.dto.generated.Account;
import org.apache.camel.component.salesforce.dto.generated.Contact;
import org.apache.camel.component.salesforce.dto.generated.ContentVersion;
import org.apache.camel.component.salesforce.dto.generated.Document;
+import org.apache.camel.component.salesforce.dto.generated.Folder;
import org.apache.camel.component.salesforce.dto.generated.Line_Item__c;
import org.apache.camel.component.salesforce.dto.generated.Merchandise__c;
import org.apache.camel.component.salesforce.dto.generated.QueryRecordsAccount;
import org.apache.camel.component.salesforce.dto.generated.QueryRecordsContact;
+import org.apache.camel.component.salesforce.dto.generated.QueryRecordsFolder;
import org.apache.camel.component.salesforce.dto.generated.QueryRecordsLine_Item__c;
import org.apache.camel.component.salesforce.dto.generated.Task;
import org.apache.camel.component.salesforce.dto.generated.User;
@@ -280,6 +282,50 @@ public class RestApiManualIT extends AbstractSalesforceTestBase {
assertNotNull(template().requestBody("salesforce:deleteSObject?sObjectName=Merchandise__c", result.getId()));
}
+ @Test
+ public void testCreateMultipart() {
+ final ContentVersion cv = new ContentVersion();
+ cv.setPathOnClient("camel-test-doc.pdf");
+ cv.setVersionDataBinary(getClass().getClassLoader().getResourceAsStream("camel-test-doc.pdf"));
+ final CreateSObjectResult result
+ = template.requestBody("salesforce:createSObject?sObjectName=ContentVersion",
+ cv,
+ CreateSObjectResult.class);
+ assertTrue(result.getSuccess());
+ }
+
+ @Test
+ public void testUpdateMultipart() {
+ final QueryRecordsFolder queryResult = template.requestBody("salesforce:query" +
+ "?sObjectQuery=SELECT Id FROM Folder WHERE Name = 'Test Documents'"
+ +
+ "&sObjectName=QueryRecordsFolder",
+ null, QueryRecordsFolder.class);
+ final Folder folder = queryResult.getRecords().get(0);
+
+ // Create a Document
+ final Document doc = new Document();
+ doc.setFolderId(folder.getId());
+ doc.setName("camel-test-doc.pdf");
+ doc.setBodyBinary(getClass().getClassLoader().getResourceAsStream("camel-test-doc.pdf"));
+ final CreateSObjectResult createResult = template.requestBody(
+ "salesforce:createSObject?sObjectName=Document",
+ doc,
+ CreateSObjectResult.class);
+ assertTrue(createResult.getSuccess());
+ assertNotNull(createResult.getId());
+
+ // Update the Document (e.g., change the name)
+ final Document updateDoc = new Document();
+ updateDoc.setId(createResult.getId());
+ updateDoc.setName("camel-test-doc-updated.pdf");
+ updateDoc.setBodyBinary(getClass().getClassLoader().getResourceAsStream("camel-test-doc.pdf"));
+ final Object updateResult = template.requestBody(
+ "salesforce:updateSObject?sObjectName=Document",
+ updateDoc);
+ assertNotNull(updateResult);
+ }
+
@Test
public void testRelationshipCreateDelete() throws Exception {
final Account account = new Account();
@@ -476,7 +522,7 @@ public class RestApiManualIT extends AbstractSalesforceTestBase {
ObjectMapper mapper = new ObjectMapper();
String enc = mapper.convertValue(bytes, String.class);
ContentVersion cv = new ContentVersion();
- cv.setVersionDataUrl(enc);
+ cv.setVersionData(enc);
cv.setPathOnClient("camel-test-doc.pdf");
cv.setTitle("Camel Test Doc");
final CreateSObjectResult result = template.requestBody("salesforce:createSObject", cv, CreateSObjectResult.class);
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/ContentVersion.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/ContentVersion.java
index 1ff87ba22ad..bd78c320f1a 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/ContentVersion.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/ContentVersion.java
@@ -19,25 +19,20 @@
*/
package org.apache.camel.component.salesforce.dto.generated;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.databind.annotation.JsonTypeResolver;
import jakarta.annotation.Generated;
-
import org.apache.camel.component.salesforce.api.dto.AbstractDescribedSObjectBase;
-import org.apache.camel.component.salesforce.api.dto.Attributes;
-import org.apache.camel.component.salesforce.api.dto.ChildRelationShip;
-import org.apache.camel.component.salesforce.api.dto.InfoUrls;
-import org.apache.camel.component.salesforce.api.dto.NamedLayoutInfo;
-import org.apache.camel.component.salesforce.api.dto.RecordTypeInfo;
import org.apache.camel.component.salesforce.api.dto.SObjectDescription;
import org.apache.camel.component.salesforce.api.dto.SObjectDescriptionUrls;
import org.apache.camel.component.salesforce.api.dto.SObjectField;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonSubTypes;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import com.fasterxml.jackson.databind.annotation.JsonTypeResolver;
import org.apache.camel.component.salesforce.api.utils.AsNestedPropertyResolver;
/**
@@ -370,14 +365,40 @@ public class ContentVersion extends AbstractDescribedSObjectBase {
this.PublishStatus = PublishStatus;
}
- private String VersionDataUrl;
+
+ private String VersionData;
@JsonProperty("VersionData")
+ public String getVersionData() {
+ return this.VersionData;
+ }
+
+ @JsonProperty("VersionData")
+ public void setVersionData(String VersionData) {
+ this.VersionData = VersionData;
+ }
+
+ @JsonIgnore
+ private InputStream VersionDataBinary;
+
+ @JsonIgnore
+ public InputStream getVersionDataBinary() {
+ return this.VersionDataBinary;
+ }
+
+ @JsonIgnore
+ public void setVersionDataBinary(InputStream VersionDataBinary) {
+ this.VersionDataBinary = VersionDataBinary;
+ }
+
+ @JsonProperty("VersionDataUrl")
public String getVersionDataUrl() {
return this.VersionDataUrl;
}
- @JsonProperty("VersionData")
+ private String VersionDataUrl;
+
+ @JsonProperty("VersionDataUrl")
public void setVersionDataUrl(String VersionDataUrl) {
this.VersionDataUrl = VersionDataUrl;
}
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/Document.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/Document.java
index 309402b3bbd..7ce44aa60cd 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/Document.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/Document.java
@@ -16,18 +16,26 @@
*/
package org.apache.camel.component.salesforce.dto.generated;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.databind.annotation.JsonTypeResolver;
+import jakarta.annotation.Generated;
import org.apache.camel.component.salesforce.api.dto.AbstractDescribedSObjectBase;
import org.apache.camel.component.salesforce.api.dto.SObjectDescription;
import org.apache.camel.component.salesforce.api.dto.SObjectDescriptionUrls;
import org.apache.camel.component.salesforce.api.dto.SObjectField;
+import org.apache.camel.component.salesforce.api.utils.AsNestedPropertyResolver;
/**
* Salesforce DTO for SObject Document
*/
+@Generated("org.apache.camel.maven.CamelSalesforceMojo")
public class Document extends AbstractDescribedSObjectBase {
public Document() {
@@ -48,6 +56,22 @@ public class Document extends AbstractDescribedSObjectBase {
this.FolderId = FolderId;
}
+ @JsonTypeResolver(AsNestedPropertyResolver.class)
+ @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "attributes.type",
+ defaultImpl = AbstractDescribedSObjectBase.class)
+ @JsonSubTypes({
+ })
+ private AbstractDescribedSObjectBase Folder;
+
+ @JsonProperty("Folder")
+ public AbstractDescribedSObjectBase getFolder() {
+ return this.Folder;
+ }
+
+ @JsonProperty("Folder")
+ public void setFolder(AbstractDescribedSObjectBase Folder) {
+ this.Folder = Folder;
+ }
private String DeveloperName;
@JsonProperty("DeveloperName")
@@ -120,17 +144,29 @@ public class Document extends AbstractDescribedSObjectBase {
this.BodyLength = BodyLength;
}
- // blob field url, use getBlobField to get the content
- private String BodyUrl;
+ private String Body;
@JsonProperty("Body")
- public String getBodyUrl() {
- return this.BodyUrl;
+ public String getBody() {
+ return this.Body;
}
@JsonProperty("Body")
- public void setBodyUrl(String BodyUrl) {
- this.BodyUrl = BodyUrl;
+ public void setBody(String Body) {
+ this.Body = Body;
+ }
+
+ @JsonIgnore
+ private InputStream bodyBinary;
+
+ @JsonIgnore
+ public InputStream getBodyBinary() {
+ return this.bodyBinary;
+ }
+
+ @JsonIgnore
+ public void setBodyBinary(InputStream bodyBinary) {
+ this.bodyBinary = bodyBinary;
}
private String Url;
@@ -193,6 +229,39 @@ public class Document extends AbstractDescribedSObjectBase {
this.AuthorId = AuthorId;
}
+ private AbstractDescribedSObjectBase Author;
+
+ @JsonProperty("Author")
+ public AbstractDescribedSObjectBase getAuthor() {
+ return this.Author;
+ }
+
+ @JsonProperty("Author")
+ public void setAuthor(AbstractDescribedSObjectBase Author) {
+ this.Author = Author;
+ }
+ private AbstractDescribedSObjectBase CreatedBy;
+
+ @JsonProperty("CreatedBy")
+ public AbstractDescribedSObjectBase getCreatedBy() {
+ return this.CreatedBy;
+ }
+
+ @JsonProperty("CreatedBy")
+ public void setCreatedBy(AbstractDescribedSObjectBase CreatedBy) {
+ this.CreatedBy = CreatedBy;
+ }
+ private AbstractDescribedSObjectBase LastModifiedBy;
+
+ @JsonProperty("LastModifiedBy")
+ public AbstractDescribedSObjectBase getLastModifiedBy() {
+ return this.LastModifiedBy;
+ }
+
+ @JsonProperty("LastModifiedBy")
+ public void setLastModifiedBy(AbstractDescribedSObjectBase LastModifiedBy) {
+ this.LastModifiedBy = LastModifiedBy;
+ }
private Boolean IsBodySearchable;
@JsonProperty("IsBodySearchable")
@@ -205,6 +274,7 @@ public class Document extends AbstractDescribedSObjectBase {
this.IsBodySearchable = IsBodySearchable;
}
+
@Override
public final SObjectDescription description() {
return DESCRIPTION;
@@ -213,6 +283,8 @@ public class Document extends AbstractDescribedSObjectBase {
private static SObjectDescription createSObjectDescription() {
final SObjectDescription description = new SObjectDescription();
+
+
final List<SObjectField> fields1 = new ArrayList<>();
description.setFields(fields1);
@@ -258,13 +330,11 @@ public class Document extends AbstractDescribedSObjectBase {
fields1.add(sObjectField20);
final SObjectField sObjectField21 = createField("SystemModstamp", "System Modstamp", "datetime", "xsd:dateTime", 0, false, false, false, false, false, false, false);
fields1.add(sObjectField21);
- final SObjectField sObjectField22 = createField("IsBodySearchable", "Document Content Searchable", "boolean", "xsd:boolean", 0, false, false, false, false, false, false,
- false);
+ final SObjectField sObjectField22 = createField("IsBodySearchable", "Document Content Searchable", "boolean", "xsd:boolean", 0, false, false, false, false, false, false, false);
fields1.add(sObjectField22);
final SObjectField sObjectField23 = createField("LastViewedDate", "Last Viewed Date", "datetime", "xsd:dateTime", 0, false, true, false, false, false, false, false);
fields1.add(sObjectField23);
- final SObjectField sObjectField24 = createField("LastReferencedDate", "Last Referenced Date", "datetime", "xsd:dateTime", 0, false, true, false, false, false, false,
- false);
+ final SObjectField sObjectField24 = createField("LastReferencedDate", "Last Referenced Date", "datetime", "xsd:dateTime", 0, false, true, false, false, false, false, false);
fields1.add(sObjectField24);
description.setLabel("Document");
@@ -272,13 +342,11 @@ public class Document extends AbstractDescribedSObjectBase {
description.setName("Document");
final SObjectDescriptionUrls sObjectDescriptionUrls1 = new SObjectDescriptionUrls();
- sObjectDescriptionUrls1.setDefaultValues("/services/data/v45.0/sobjects/Document/defaultValues?recordTypeId&fields");
- sObjectDescriptionUrls1.setDescribe("/services/data/v45.0/sobjects/Document/describe");
- sObjectDescriptionUrls1.setRowTemplate("/services/data/v45.0/sobjects/Document/{ID}");
- sObjectDescriptionUrls1.setSobject("/services/data/v45.0/sobjects/Document");
+ sObjectDescriptionUrls1.setDescribe("/services/data/v59.0/sobjects/Document/describe");
+ sObjectDescriptionUrls1.setRowTemplate("/services/data/v59.0/sobjects/Document/{ID}");
+ sObjectDescriptionUrls1.setSobject("/services/data/v59.0/sobjects/Document");
description.setUrls(sObjectDescriptionUrls1);
return description;
}
}
-
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/Folder.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/Folder.java
new file mode 100644
index 00000000000..7c21b55fda5
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/Folder.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.
+ */
+/*
+ * Salesforce DTO generated by camel-salesforce-maven-plugin.
+ */
+package org.apache.camel.component.salesforce.dto.generated;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import jakarta.annotation.Generated;
+import org.apache.camel.component.salesforce.api.dto.AbstractDescribedSObjectBase;
+import org.apache.camel.component.salesforce.api.dto.SObjectDescription;
+import org.apache.camel.component.salesforce.api.dto.SObjectDescriptionUrls;
+import org.apache.camel.component.salesforce.api.dto.SObjectField;
+
+/**
+ * Salesforce DTO for SObject Folder
+ */
+@Generated("org.apache.camel.maven.CamelSalesforceMojo")
+public class Folder extends AbstractDescribedSObjectBase {
+
+ public Folder() {
+ getAttributes().setType("Folder");
+ }
+
+ private static final SObjectDescription DESCRIPTION = createSObjectDescription();
+
+ private String ParentId;
+
+ @JsonProperty("ParentId")
+ public String getParentId() {
+ return this.ParentId;
+ }
+
+ @JsonProperty("ParentId")
+ public void setParentId(String ParentId) {
+ this.ParentId = ParentId;
+ }
+
+ private String DeveloperName;
+
+ @JsonProperty("DeveloperName")
+ public String getDeveloperName() {
+ return this.DeveloperName;
+ }
+
+ @JsonProperty("DeveloperName")
+ public void setDeveloperName(String DeveloperName) {
+ this.DeveloperName = DeveloperName;
+ }
+
+ private String AccessType;
+
+ @JsonProperty("AccessType")
+ public String getAccessType() {
+ return this.AccessType;
+ }
+
+ @JsonProperty("AccessType")
+ public void setAccessType(String AccessType) {
+ this.AccessType = AccessType;
+ }
+
+ private Boolean IsReadonly;
+
+ @JsonProperty("IsReadonly")
+ public Boolean getIsReadonly() {
+ return this.IsReadonly;
+ }
+
+ @JsonProperty("IsReadonly")
+ public void setIsReadonly(Boolean IsReadonly) {
+ this.IsReadonly = IsReadonly;
+ }
+
+ private String Type;
+
+ @JsonProperty("Type")
+ public String getType() {
+ return this.Type;
+ }
+
+ @JsonProperty("Type")
+ public void setType(String Type) {
+ this.Type = Type;
+ }
+
+ private String NamespacePrefix;
+
+ @JsonProperty("NamespacePrefix")
+ public String getNamespacePrefix() {
+ return this.NamespacePrefix;
+ }
+
+ @JsonProperty("NamespacePrefix")
+ public void setNamespacePrefix(String NamespacePrefix) {
+ this.NamespacePrefix = NamespacePrefix;
+ }
+
+ private AbstractDescribedSObjectBase CreatedBy;
+
+ @JsonProperty("CreatedBy")
+ public AbstractDescribedSObjectBase getCreatedBy() {
+ return this.CreatedBy;
+ }
+
+ @JsonProperty("CreatedBy")
+ public void setCreatedBy(AbstractDescribedSObjectBase CreatedBy) {
+ this.CreatedBy = CreatedBy;
+ }
+ private AbstractDescribedSObjectBase LastModifiedBy;
+
+ @JsonProperty("LastModifiedBy")
+ public AbstractDescribedSObjectBase getLastModifiedBy() {
+ return this.LastModifiedBy;
+ }
+
+ @JsonProperty("LastModifiedBy")
+ public void setLastModifiedBy(AbstractDescribedSObjectBase LastModifiedBy) {
+ this.LastModifiedBy = LastModifiedBy;
+ }
+ private QueryRecordsFolder SubFolders;
+
+ @JsonProperty("SubFolders")
+ public QueryRecordsFolder getSubFolders() {
+ return SubFolders;
+ }
+
+ @JsonProperty("SubFolders")
+ public void setSubFolders(QueryRecordsFolder SubFolders) {
+ this.SubFolders = SubFolders;
+ }
+
+ @Override
+ public final SObjectDescription description() {
+ return DESCRIPTION;
+ }
+
+ private static SObjectDescription createSObjectDescription() {
+ final SObjectDescription description = new SObjectDescription();
+
+
+
+ final List<SObjectField> fields1 = new ArrayList<>();
+ description.setFields(fields1);
+
+ final SObjectField sObjectField1 = createField("Id", "Folder ID", "id", "tns:ID", 18, false, false, false, false, false, false, true);
+ fields1.add(sObjectField1);
+ final SObjectField sObjectField2 = createField("ParentId", "Folder ID", "reference", "tns:ID", 18, false, true, false, false, false, false, false);
+ fields1.add(sObjectField2);
+ final SObjectField sObjectField3 = createField("Name", "Name", "string", "xsd:string", 40, false, false, true, false, false, false, true);
+ fields1.add(sObjectField3);
+ final SObjectField sObjectField4 = createField("DeveloperName", "Folder Unique Name", "string", "xsd:string", 80, false, true, false, false, false, false, false);
+ fields1.add(sObjectField4);
+ final SObjectField sObjectField5 = createField("AccessType", "Access Type", "picklist", "xsd:string", 40, false, false, false, false, false, false, false);
+ fields1.add(sObjectField5);
+ final SObjectField sObjectField6 = createField("IsReadonly", "Read Only", "boolean", "xsd:boolean", 0, false, false, false, false, false, false, false);
+ fields1.add(sObjectField6);
+ final SObjectField sObjectField7 = createField("Type", "Type", "picklist", "xsd:string", 40, false, false, false, false, false, false, false);
+ fields1.add(sObjectField7);
+ final SObjectField sObjectField8 = createField("NamespacePrefix", "Namespace Prefix", "string", "xsd:string", 15, false, true, false, false, false, false, false);
+ fields1.add(sObjectField8);
+ final SObjectField sObjectField9 = createField("CreatedDate", "Created Date", "datetime", "xsd:dateTime", 0, false, false, false, false, false, false, false);
+ fields1.add(sObjectField9);
+ final SObjectField sObjectField10 = createField("CreatedById", "Created By ID", "reference", "tns:ID", 18, false, false, false, false, false, false, false);
+ fields1.add(sObjectField10);
+ final SObjectField sObjectField11 = createField("LastModifiedDate", "Last Modified Date", "datetime", "xsd:dateTime", 0, false, false, false, false, false, false, false);
+ fields1.add(sObjectField11);
+ final SObjectField sObjectField12 = createField("LastModifiedById", "Last Modified By ID", "reference", "tns:ID", 18, false, false, false, false, false, false, false);
+ fields1.add(sObjectField12);
+ final SObjectField sObjectField13 = createField("SystemModstamp", "System Modstamp", "datetime", "xsd:dateTime", 0, false, false, false, false, false, false, false);
+ fields1.add(sObjectField13);
+
+ description.setLabel("Folder");
+ description.setLabelPlural("Folders");
+ description.setName("Folder");
+
+ final SObjectDescriptionUrls sObjectDescriptionUrls1 = new SObjectDescriptionUrls();
+ sObjectDescriptionUrls1.setDescribe("/services/data/v59.0/sobjects/Folder/describe");
+ sObjectDescriptionUrls1.setRowTemplate("/services/data/v59.0/sobjects/Folder/{ID}");
+ sObjectDescriptionUrls1.setSobject("/services/data/v59.0/sobjects/Folder");
+ description.setUrls(sObjectDescriptionUrls1);
+
+ return description;
+ }
+}
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/QueryRecordsFolder.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/QueryRecordsFolder.java
new file mode 100644
index 00000000000..50a2706fc60
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/QueryRecordsFolder.java
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+/*
+ * Salesforce Query DTO generated by camel-salesforce-maven-plugin
+ */
+package org.apache.camel.component.salesforce.dto.generated;
+
+import jakarta.annotation.Generated;
+import org.apache.camel.component.salesforce.api.dto.AbstractQueryRecordsBase;
+
+/**
+ * Salesforce QueryRecords DTO for type Folder
+ */
+@Generated("org.apache.camel.maven.CamelSalesforceMojo")
+public class QueryRecordsFolder extends AbstractQueryRecordsBase<Folder> {
+}