camel-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From acosent...@apache.org
Subject [camel] branch master updated: Camel-Salesforce: null serialization at the SObject and field level
Date Thu, 29 Aug 2019 06:32:01 GMT
This is an automated email from the ASF dual-hosted git repository.

acosentino 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 90df2f7  Camel-Salesforce: null serialization at the SObject and field level
     new 6af791e  Merge pull request #3129 from jeremyross/master
90df2f7 is described below

commit 90df2f79bc4524f997f5a415e6aca96a894e4d47
Author: Jeremy Ross <jeremy@jeremyross.org>
AuthorDate: Tue Aug 27 11:26:21 2019 -0500

    Camel-Salesforce: null serialization at the SObject and field level
    
    * Ability to set which fields get serialized at the per-SObject
      and per-field level
    
    * Fix: Serializes null values for all multipicklist fields for which
      a value is not set, regardless of the `serializeNulls` setting
---
 .../camel-salesforce-component/pom.xml             |   5 +
 .../src/main/docs/salesforce-component.adoc        |  13 ++-
 .../salesforce/SalesforceEndpointConfig.java       |  19 +---
 .../salesforce/api/FieldsToNullPropertyFilter.java |  42 ++++++++
 .../salesforce/api/dto/AbstractDTOBase.java        |   4 +-
 .../salesforce/api/dto/AbstractSObjectBase.java    |  20 ++++
 .../component/salesforce/api/dto/Attributes.java   |   2 +-
 .../component/salesforce/api/utils/JsonUtils.java  |   6 ++
 .../internal/processor/JsonRestProcessor.java      |  22 +---
 .../salesforce/RestApiIntegrationTest.java         |  61 ++++++++++-
 .../api/MultiSelectPicklistJsonTest.java           |  18 +++-
 .../api/dto/composite/SObjectBatchTest.java        | 112 +++++++++++++++++----
 .../api/dto/composite/SObjectTreeTest.java         |  66 +++++++++---
 .../salesforce/dto/generated/Account.java          |   2 -
 .../salesforce/dto/generated/Contact.java          |   1 -
 .../salesforce/dto/generated/Document.java         |   4 +-
 .../salesforce/dto/generated/StringMSPTest.java    |   1 -
 .../component/salesforce/dto/generated/Task.java   |  18 ++++
 .../internal/processor/JsonRestProcessorTest.java  |  58 ++++-------
 .../api/dto/composite_request_example.json         |  12 ++-
 .../java/org/apache/camel/maven/GenerateMojo.java  |   1 -
 .../src/main/resources/sobject-pojo.vm             |   7 +-
 .../camel/maven/CamelSalesforceMojoOutputTest.java |  26 +++--
 .../src/test/resources/generated/Asset.java        |   6 +-
 .../resources/generated/Asset_LocalDateTime.java   |   6 +-
 .../src/test/resources/generated/Case.java         |   6 +-
 .../generated/ComplexCalculatedFormula.java        |   6 +-
 .../resources/generated/With_Reference__c.java     |   6 +-
 .../dsl/SalesforceEndpointBuilderFactory.java      |  76 --------------
 .../SalesforceComponentConfiguration.java          |  13 ---
 30 files changed, 385 insertions(+), 254 deletions(-)

diff --git a/components/camel-salesforce/camel-salesforce-component/pom.xml b/components/camel-salesforce/camel-salesforce-component/pom.xml
index 2932aee..d39f932 100644
--- a/components/camel-salesforce/camel-salesforce-component/pom.xml
+++ b/components/camel-salesforce/camel-salesforce-component/pom.xml
@@ -122,6 +122,11 @@
                 </exclusion>
             </exclusions>
         </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>${commons-lang3-version}</version>
+        </dependency>
 
         <!-- logging -->
         <dependency>
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 80cc134..441e3c1 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
@@ -575,6 +575,16 @@ final Map<String, ?> accountUpdateBody = accountUpdateResult.getBody();
 final SObjectCompositeResult contactCreationResult = results.stream().filter(r -> "JunctionRecord".equals(r.getReferenceId())).findFirst().get()
 ----
 
+==  Sending null values to salesforce
+
+By default, SObject fields with null values are not sent to salesforce. In order to
+send null values to salesforce, use the `fieldsToNull` property, as follows:
+
+[source,java]
+----
+accountSObject.getFieldsToNull().add("Site");
+----
+
 == Generating SOQL query strings
 
 `org.apache.camel.component.salesforce.api.utils.QueryHelper` contains helper
@@ -689,7 +699,7 @@ with the following path and query parameters:
 |===
 
 
-=== Query Parameters (46 parameters):
+=== Query Parameters (45 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -723,7 +733,6 @@ with the following path and query parameters:
 | *reportId* (common) | Salesforce1 Analytics report Id |  | String
 | *reportMetadata* (common) | Salesforce1 Analytics report metadata for filtering |  | ReportMetadata
 | *resultId* (common) | Bulk API Result ID |  | String
-| *serializeNulls* (common) | Should the NULL values of given DTO be serialized with empty (NULL) values. This affects only JSON data format. | false | boolean
 | *sObjectBlobFieldName* (common) | SObject blob field name |  | String
 | *sObjectClass* (common) | Fully qualified SObject class name, usually generated using camel-salesforce-maven-plugin |  | String
 | *sObjectFields* (common) | SObject fields to retrieve |  | String
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 098883a..1338461 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
@@ -96,8 +96,6 @@ public class SalesforceEndpointConfig implements Cloneable {
 
     public static final String NOT_FOUND_BEHAVIOUR = "notFoundBehaviour";
 
-    public static final String SERIALIZE_NULLS = "serializeNulls";
-
     // general properties
     @UriParam
     private String apiVersion = DEFAULT_VERSION;
@@ -125,8 +123,6 @@ public class SalesforceEndpointConfig implements Cloneable {
     private String sObjectQuery;
     @UriParam(displayName = "SObject Search")
     private String sObjectSearch;
-    @UriParam(displayName = "Serialize NULL values")
-    private boolean serializeNulls;
     @UriParam
     private String apexMethod;
     @UriParam
@@ -348,18 +344,6 @@ public class SalesforceEndpointConfig implements Cloneable {
         this.sObjectSearch = sObjectSearch;
     }
 
-    /**
-     * Should the NULL values of given DTO be serialized with empty (NULL)
-     * values. This affects only JSON data format.
-     */
-    public void setSerializeNulls(boolean serializeNulls) {
-        this.serializeNulls = serializeNulls;
-    }
-
-    public boolean isSerializeNulls() {
-        return serializeNulls;
-    }
-
     public String getApexMethod() {
         return apexMethod;
     }
@@ -637,7 +621,6 @@ public class SalesforceEndpointConfig implements Cloneable {
         valueMap.put(SOBJECT_CLASS, sObjectClass);
         valueMap.put(SOBJECT_QUERY, sObjectQuery);
         valueMap.put(SOBJECT_SEARCH, sObjectSearch);
-        valueMap.put(SERIALIZE_NULLS, serializeNulls);
         valueMap.put(APEX_METHOD, apexMethod);
         valueMap.put(APEX_URL, apexUrl);
         valueMap.put(LIMIT, limit);
@@ -832,7 +815,7 @@ public class SalesforceEndpointConfig implements Cloneable {
      * If the process requires specification of the next approval, the ID of the
      * user to be assigned the next request.
      *
-     * @param nextApproverIds
+     * @param nextApproverId
      */
     public void setApprovalNextApproverIds(String nextApproverId) {
         if (approval == null) {
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/FieldsToNullPropertyFilter.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/FieldsToNullPropertyFilter.java
new file mode 100644
index 0000000..ba86bf7
--- /dev/null
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/FieldsToNullPropertyFilter.java
@@ -0,0 +1,42 @@
+/*
+ * 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;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.PropertyWriter;
+import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
+import org.apache.camel.component.salesforce.api.dto.AbstractSObjectBase;
+import org.apache.commons.lang3.reflect.FieldUtils;
+
+public class FieldsToNullPropertyFilter extends SimpleBeanPropertyFilter {
+
+    @Override
+    public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider provider,
+            PropertyWriter writer) throws Exception {
+
+        AbstractSObjectBase sob = (AbstractSObjectBase) pojo;
+        String fieldName = writer.getName();
+        Object fieldValue = FieldUtils.readField(pojo, fieldName, true);
+        if (sob.getFieldsToNull().contains(writer.getName()) || fieldValue != null) {
+            writer.serializeAsField(pojo, jgen, provider);
+        }
+        else {
+            writer.serializeAsOmittedField(pojo, jgen, provider);
+        }
+    }
+}
\ No newline at end of file
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractDTOBase.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractDTOBase.java
index 707d872..4558b6c 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractDTOBase.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractDTOBase.java
@@ -19,14 +19,12 @@ package org.apache.camel.component.salesforce.api.dto;
 import java.io.IOException;
 import java.io.StringWriter;
 
+import com.fasterxml.jackson.annotation.JsonFilter;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.databind.ObjectMapper;
 
 import org.apache.camel.component.salesforce.api.utils.JsonUtils;
 
-// disable null values in json output
-@JsonInclude(JsonInclude.Include.NON_NULL)
 // avoid running into Salesforce backward compatibility breaks
 @JsonIgnoreProperties(ignoreUnknown = true)
 public abstract class AbstractDTOBase {
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractSObjectBase.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractSObjectBase.java
index 09cecd7..53b1f8c 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractSObjectBase.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/AbstractSObjectBase.java
@@ -17,11 +17,16 @@
 package org.apache.camel.component.salesforce.api.dto;
 
 import java.time.ZonedDateTime;
+import java.util.HashSet;
+import java.util.Set;
 
+import com.fasterxml.jackson.annotation.JsonFilter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.thoughtworks.xstream.annotations.XStreamOmitField;
 
 //CHECKSTYLE:OFF
+@JsonFilter("fieldsToNull")
 public abstract class AbstractSObjectBase extends AbstractDTOBase {
 
     // WARNING: these fields have case sensitive names,
@@ -42,6 +47,9 @@ public abstract class AbstractSObjectBase extends AbstractDTOBase {
     private ZonedDateTime LastViewedDate;
     private ZonedDateTime LastReferencedDate;
 
+    @XStreamOmitField
+    private Set<String> fieldsToNull = new HashSet<>();
+
     public AbstractSObjectBase() {
         attributes = new Attributes();
     }
@@ -57,6 +65,7 @@ public abstract class AbstractSObjectBase extends AbstractDTOBase {
      * </p>
      */
     public final void clearBaseFields() {
+//
         attributes = null;
         Id = null;
         IsDeleted = null;
@@ -197,5 +206,16 @@ public abstract class AbstractSObjectBase extends AbstractDTOBase {
     public void setLastReferencedDate(ZonedDateTime lastReferencedDate) {
         LastReferencedDate = lastReferencedDate;
     }
+
+    @JsonIgnore
+    public Set<String> getFieldsToNull() {
+        return fieldsToNull;
+    }
+
+    @JsonIgnore
+    public void setFieldsToNull(Set<String> fieldsToNull) {
+        this.fieldsToNull = fieldsToNull;
+    }
+
 }
 //CHECKSTYLE:ON
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/Attributes.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/Attributes.java
index 08a289c..50e7e8d 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/Attributes.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/Attributes.java
@@ -21,7 +21,7 @@ import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
 public class Attributes extends AbstractDTOBase {
     
     @XStreamAsAttribute
-    String referenceId;
+    private String referenceId;
     
     @XStreamAsAttribute
     private String type;
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/utils/JsonUtils.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/utils/JsonUtils.java
index 9598a1b..527151b 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/utils/JsonUtils.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/utils/JsonUtils.java
@@ -24,6 +24,7 @@ import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
 import static java.util.stream.Collectors.joining;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
@@ -52,6 +53,7 @@ import com.fasterxml.jackson.module.jsonSchema.types.ObjectSchema;
 import com.fasterxml.jackson.module.jsonSchema.types.SimpleTypeSchema;
 import com.fasterxml.jackson.module.jsonSchema.types.StringSchema;
 
+import org.apache.camel.component.salesforce.api.FieldsToNullPropertyFilter;
 import org.apache.camel.component.salesforce.api.dto.AbstractDTOBase;
 import org.apache.camel.component.salesforce.api.dto.AbstractQueryRecordsBase;
 import org.apache.camel.component.salesforce.api.dto.Address;
@@ -77,9 +79,13 @@ public abstract class JsonUtils {
     public static ObjectMapper createObjectMapper() {
         // enable date time support including Java 1.8 ZonedDateTime
         ObjectMapper objectMapper = new ObjectMapper();
+        SimpleFilterProvider filterProvider = new SimpleFilterProvider()
+                .addFilter("fieldsToNull", new FieldsToNullPropertyFilter());
+        objectMapper.setFilterProvider(filterProvider);
         objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
         objectMapper.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);
         objectMapper.registerModule(new TimeModule());
+        
         return objectMapper;
     }
 
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessor.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessor.java
index 66908a6..d09d1d3 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessor.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessor.java
@@ -57,11 +57,7 @@ public class JsonRestProcessor extends AbstractRestProcessor {
         if (endpoint.getConfiguration().getObjectMapper() != null) {
             this.objectMapper = endpoint.getConfiguration().getObjectMapper();
         } else {
-            if (endpoint.getConfiguration().isSerializeNulls()) {
-                this.objectMapper = JsonUtils.withNullSerialization(JsonUtils.createObjectMapper());
-            } else {
-                this.objectMapper = JsonUtils.createObjectMapper();
-            }
+            this.objectMapper = JsonUtils.createObjectMapper();
         }
     }
 
@@ -163,7 +159,7 @@ public class JsonRestProcessor extends AbstractRestProcessor {
     protected InputStream getRequestStream(final Message in, final Object object) throws SalesforceException {
         final ByteArrayOutputStream out = new ByteArrayOutputStream();
         try {
-            prepareMapper(in).writeValue(out, object);
+            objectMapper.writeValue(out, object);
         } catch (IOException e) {
             final String msg = "Error marshaling request: " + e.getMessage();
             throw new SalesforceException(msg, e);
@@ -192,11 +188,11 @@ public class JsonRestProcessor extends AbstractRestProcessor {
                 final Object response;
                 Class<?> responseClass = exchange.getProperty(RESPONSE_CLASS, Class.class);
                 if (!rawPayload && responseClass != null) {
-                    response = prepareMapper(in).readValue(responseEntity, responseClass);
+                    response = objectMapper.readValue(responseEntity, responseClass);
                 } else {
                     TypeReference<?> responseType = exchange.getProperty(RESPONSE_TYPE, TypeReference.class);
                     if (!rawPayload && responseType != null) {
-                        response = prepareMapper(in).readValue(responseEntity, responseType);
+                        response = objectMapper.readValue(responseEntity, responseType);
                     } else {
                         // return the response as a stream, for getBlobField
                         response = responseEntity;
@@ -225,14 +221,4 @@ public class JsonRestProcessor extends AbstractRestProcessor {
         }
 
     }
-
-    private ObjectMapper prepareMapper(final Message in) {
-        final Object serializeNulls = in.getHeader(SalesforceEndpointConfig.SERIALIZE_NULLS);
-        if (Boolean.TRUE.equals(serializeNulls)) {
-            return JsonUtils.withNullSerialization(objectMapper);
-        }
-
-        return objectMapper;
-    }
-
 }
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
index fca975e..44ddf3c 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/RestApiIntegrationTest.java
@@ -238,7 +238,7 @@ public class RestApiIntegrationTest extends AbstractSalesforceTestBase {
         contact.setAccount(accountRef);
         contact.setLastName("RelationshipTest");
         final CreateSObjectResult contactResult = template().requestBody("direct:createSObject", contact, CreateSObjectResult.class);
-        assertNotNull(accountResult);
+        assertNotNull(contactResult);
         assertTrue("Create success", contactResult.getSuccess());
 
         // delete the Contact
@@ -246,7 +246,66 @@ public class RestApiIntegrationTest extends AbstractSalesforceTestBase {
 
         // delete the Account
         template().requestBodyAndHeader("direct:deleteSObject", accountResult.getId(), "sObjectName", "Account");
+    }
+
+    @Test
+    public void testFieldsToNull() throws Exception {
+        final Account account = new Account();
+        account.setName("Account 1");
+        account.setSite("test site");
+        final CreateSObjectResult accountResult = template().requestBody("direct:createSObject",
+                account, CreateSObjectResult.class);
+        assertNotNull(accountResult);
+        assertTrue("Create success", accountResult.getSuccess());
+
+        account.setId(accountResult.getId());
+        account.setSite(null);
+        account.getFieldsToNull().add("Site");
+
+        final Object updateAccountResult = template().requestBodyAndHeader("salesforce:updateSObject", account,
+                SalesforceEndpointConfig.SOBJECT_ID, account.getId());
+        assertNull(updateAccountResult);
+
+        Account updatedAccount = (Account) template().requestBodyAndHeader(
+                "salesforce:getSObject?sObjectFields=Id,Name,Site", account.getId(),
+                "sObjectName", "Account");
+        assertNull(updatedAccount.getSite());
+
+        // delete the Account
+        template().requestBodyAndHeader("direct:deleteSObject", accountResult.getId(), "sObjectName", "Account");
+    }
+
+    @Test
+    public void testRelationshipUpdate() throws Exception {
+        final Contact contact = new Contact();
+        contact.setLastName("RelationshipTest");
+        final CreateSObjectResult contactResult = template().requestBody("direct:createSObject", contact, CreateSObjectResult.class);
+        assertNotNull(contactResult);
+        assertTrue("Create success", contactResult.getSuccess());
+
+        final Account account = new Account();
+        account.setName("Account 1");
+        String accountExternalId = UUID.randomUUID().toString();
+        account.setExternal_Id__c(accountExternalId);
+        final CreateSObjectResult accountResult = template().requestBody("direct:createSObject", account, CreateSObjectResult.class);
+        assertNotNull(accountResult);
+        assertTrue("Create success", accountResult.getSuccess());
+
+        final Account accountRef = new Account();
+        accountRef.setExternal_Id__c(accountExternalId);
+        contact.setAccount(accountRef);
+        contact.setId(contactResult.getId());
+
+        final Object updateContactResult = template().requestBodyAndHeader("salesforce:updateSObject", contact,
+                SalesforceEndpointConfig.SOBJECT_ID, contact.getId());
+        assertNull(updateContactResult);
+
 
+        // delete the Contact
+        template().requestBodyAndHeader("direct:deleteSObject", contactResult.getId(), "sObjectName", "Contact");
+
+        // delete the Account
+        template().requestBodyAndHeader("direct:deleteSObject", accountResult.getId(), "sObjectName", "Account");
     }
 
     @Test
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/MultiSelectPicklistJsonTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/MultiSelectPicklistJsonTest.java
index 0e61bc8..dae2dbf 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/MultiSelectPicklistJsonTest.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/MultiSelectPicklistJsonTest.java
@@ -29,8 +29,9 @@ import static org.junit.Assert.assertNull;
 
 public class MultiSelectPicklistJsonTest {
 
-    private static final String TEST_JSON = "{\"attributes\":{\"type\":\"MSPTest\"},\"MspField\":\"Value1;Value2;Value3\"}";
-    private static final String TEST_NULL_JSON = "{\"attributes\":{\"type\":\"MSPTest\"},\"MspField\":null}";
+    private static final String TEST_JSON = "{\"attributes\":{\"referenceId\":null,\"type\":\"MSPTest\",\"url\":null},\"MspField\":\"Value1;Value2;Value3\"}";
+    private static final String TEST_NO_NULL_JSON = "{\"attributes\":{\"referenceId\":null,\"type\":\"MSPTest\",\"url\":null}}";
+    private static final String TEST_NULL_JSON = "{\"attributes\":{\"referenceId\":null,\"type\":\"MSPTest\",\"url\":null},\"MspField\":null}";
 
     private static ObjectMapper objectMapper = JsonUtils.createObjectMapper();
 
@@ -44,12 +45,24 @@ public class MultiSelectPicklistJsonTest {
 
         // test null
         mspTest.setMspField(null);
+        mspTest.getFieldsToNull().add("MspField");
 
         json = objectMapper.writeValueAsString(mspTest);
         assertEquals(TEST_NULL_JSON, json);
     }
 
     @Test
+    public void testMarshalDoesntSerializeNulls() throws Exception {
+        final MSPTest mspTest = new MSPTest();
+        mspTest.setMspField(MSPTest.MSPEnum.values());
+        // setting no null, but not including in fieldsToNull
+        mspTest.setMspField(null);
+
+        String json = objectMapper.writeValueAsString(mspTest);
+        assertEquals(TEST_NO_NULL_JSON, json);
+    }
+
+    @Test
     public void testUnmarshal() throws Exception {
         MSPTest mspTest = objectMapper.readValue(TEST_JSON, MSPTest.class);
         assertArrayEquals(MSPTest.MSPEnum.values(), mspTest.getMspField());
@@ -70,6 +83,7 @@ public class MultiSelectPicklistJsonTest {
 
         // test null
         mspTest.setMspField(null);
+        mspTest.getFieldsToNull().add("MspField");
 
         json = objectMapper.writeValueAsString(mspTest);
         assertEquals(TEST_NULL_JSON, json);
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/composite/SObjectBatchTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/composite/SObjectBatchTest.java
index 5c0d7ce9..f2bb9c6 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/composite/SObjectBatchTest.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/composite/SObjectBatchTest.java
@@ -77,29 +77,97 @@ public class SObjectBatchTest {
 
     @Test
     public void shouldSerializeToJson() throws JsonProcessingException {
-        final String json = Pattern.compile("\\s+(?=([^\"]*\"[^\"]*\")*[^\"]*$)", Pattern.DOTALL)
-            .matcher("{\n" + "  \"batchRequests\": [\n" + "    {\n" + "      \"method\": \"POST\",\n" + "      \"url\": \"v37.0/sobjects/Account/\",\n" + "      \"richInput\": {\n"
-                     + "        \"attributes\": {\n" + "          \"type\": \"Account\"\n" + "        },\n" + "        \"Industry\": \"Environmental\",\n"
-                     + "        \"Name\": \"NewAccountName\"\n" + "      }\n" + "    },\n" + "    {\n" + "      \"method\": \"DELETE\",\n"
-                     + "      \"url\": \"v37.0/sobjects/Account/001D000000K0fXOIAZ\"\n" + "    },\n" + "    {\n" + "      \"method\": \"GET\",\n"
-                     + "      \"url\": \"v37.0/sobjects/Account/001D000000K0fXOIAZ?fields=Name,BillingPostalCode\"\n" + "    },\n" + "    {\n" + "      \"method\": \"GET\",\n"
-                     + "      \"url\": \"v37.0/sobjects/Account/EPK/12345\"\n" + "    },\n" + "    {\n" + "      \"method\": \"GET\",\n"
-                     + "      \"url\": \"v37.0/sobjects/Account/001D000000K0fXOIAZ/CreatedBy?fields=Name\"\n" + "    },\n" + "    {\n" + "      \"method\": \"GET\",\n"
-                     + "      \"url\": \"v37.0/limits/\"\n" + "    },\n" + "    {\n" + "      \"method\": \"PATCH\",\n"
-                     + "      \"url\": \"v37.0/sobjects/Account/001D000000K0fXOIAZ\",\n" + "      \"richInput\": {\n" + "        \"attributes\": {\n"
-                     + "          \"type\": \"Account\"\n" + "        },\n" + "        \"AccountNumber\": \"AC12345\",\n" + "        \"Name\": \"NewName\"\n" + "      }\n"
-                     + "    },\n" + "    {\n" + "      \"method\": \"PATCH\",\n" + "      \"url\": \"v37.0/sobjects/Account/EPK/12345\",\n" + "      \"richInput\": {\n"
-                     + "        \"attributes\": {\n" + "          \"type\": \"Account\"\n" + "        },\n" + "        \"Name\": \"NewName\"\n" + "      }\n" + "    },\n"
-                     + "    {\n" + "      \"method\": \"PATCH\",\n" + "      \"url\": \"v37.0/sobjects/Account/EPK/12345\",\n" + "      \"richInput\": {\n"
-                     + "        \"attributes\": {\n" + "          \"type\": \"Account\"\n" + "        },\n" + "        \"Name\": \"NewName\"\n" + "      }\n" + "    },\n"
-                     + "    {\n" + "      \"method\": \"PATCH\",\n" + "      \"url\": \"v37.0/some/url\"\n" + "    },\n" + "    {\n" + "      \"method\": \"GET\",\n"
-                     + "      \"url\": \"v37.0/query/?q=SELECT Name FROM Account\"\n" + "    },\n" + "    {\n" + "      \"method\": \"GET\",\n"
-                     + "      \"url\": \"v37.0/queryAll/?q=SELECT Name FROM Account\"\n" + "    },\n" + "    {\n" + "      \"method\": \"GET\",\n"
-                     + "      \"url\": \"v37.0/search/?q=FIND {joe}\"\n" + "    }\n" + "  ]\n" + "}")
-            .replaceAll("");
-
+        final String json = "{" +
+                "\"batchRequests\":[" +
+                "{" +
+                "\"method\":\"POST\"," +
+                "\"url\":\"v37.0/sobjects/Account/\"," +
+                "\"richInput\":{" +
+                "\"attributes\":{" +
+                "\"referenceId\":null," +
+                "\"type\":\"Account\"," +
+                "\"url\":null" +
+                "}," +
+                "\"Industry\":\"Environmental\"," +
+                "\"Name\":\"NewAccountName\"" +
+                "}" +
+                "}," +
+                "{" +
+                "\"method\":\"DELETE\"," +
+                "\"url\":\"v37.0/sobjects/Account/001D000000K0fXOIAZ\"" +
+                "}," +
+                "{" +
+                "\"method\":\"GET\"," +
+                "\"url\":\"v37.0/sobjects/Account/001D000000K0fXOIAZ?fields=Name,BillingPostalCode\"" +
+                "}," +
+                "{" +
+                "\"method\":\"GET\"," +
+                "\"url\":\"v37.0/sobjects/Account/EPK/12345\"" +
+                "}," +
+                "{" +
+                "\"method\":\"GET\"," +
+                "\"url\":\"v37.0/sobjects/Account/001D000000K0fXOIAZ/CreatedBy?fields=Name\"" +
+                "}," +
+                "{" +
+                "\"method\":\"GET\"," +
+                "\"url\":\"v37.0/limits/\"" +
+                "}," +
+                "{" +
+                "\"method\":\"PATCH\"," +
+                "\"url\":\"v37.0/sobjects/Account/001D000000K0fXOIAZ\"," +
+                "\"richInput\":{" +
+                "\"attributes\":{" +
+                "\"referenceId\":null," +
+                "\"type\":\"Account\"," +
+                "\"url\":null" +
+                "}," +
+                "\"AccountNumber\":\"AC12345\"," +
+                "\"Name\":\"NewName\"" +
+                "}" +
+                "}," +
+                "{" +
+                "\"method\":\"PATCH\"," +
+                "\"url\":\"v37.0/sobjects/Account/EPK/12345\"," +
+                "\"richInput\":{" +
+                "\"attributes\":{" +
+                "\"referenceId\":null," +
+                "\"type\":\"Account\"," +
+                "\"url\":null" +
+                "}," +
+                "\"Name\":\"NewName\"" +
+                "}" +
+                "}," +
+                "{" +
+                "\"method\":\"PATCH\"," +
+                "\"url\":\"v37.0/sobjects/Account/EPK/12345\"," +
+                "\"richInput\":{" +
+                "\"attributes\":{" +
+                "\"referenceId\":null," +
+                "\"type\":\"Account\"," +
+                "\"url\":null" +
+                "}," +
+                "\"Name\":\"NewName\"" +
+                "}" +
+                "}," +
+                "{" +
+                "\"method\":\"PATCH\"," +
+                "\"url\":\"v37.0/some/url\"" +
+                "}," +
+                "{" +
+                "\"method\":\"GET\"," +
+                "\"url\":\"v37.0/query/?q=SELECT Name FROM Account\"" +
+                "}," +
+                "{" +
+                "\"method\":\"GET\"," +
+                "\"url\":\"v37.0/queryAll/?q=SELECT Name FROM Account\"" +
+                "}," +
+                "{" +
+                "\"method\":\"GET\"," +
+                "\"url\":\"v37.0/search/?q=FIND {joe}\"" +
+                "}" +
+                "]" +
+                "}";
         final ObjectMapper mapper = JsonUtils.createObjectMapper();
-
         final String serialized = mapper.writerFor(SObjectBatch.class).writeValueAsString(batch);
         assertEquals("Should serialize as expected by Salesforce", json, serialized);
     }
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/composite/SObjectTreeTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/composite/SObjectTreeTest.java
index ec7f25a..4720f63 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/composite/SObjectTreeTest.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/composite/SObjectTreeTest.java
@@ -73,19 +73,59 @@ public class SObjectTreeTest extends CompositeTestBase {
         tree.addNode(account2);
 
         final String json = writer.writeValueAsString(tree);
-
-        assertEquals("Should serialize to JSON as in Salesforce example",
-                     "{" + "\"records\":[" + "{" + "\"Industry\":\"Banking\"," + "\"Name\":\"SampleAccount\"," + "\"NumberOfEmployees\":100," + "\"Phone\":\"1234567890\","
-                                                                          + "\"Website\":\"www.salesforce.com\"," + "\"attributes\":{" + "\"referenceId\":\"ref1\","
-                                                                          + "\"type\":\"Account\"" + "}," + "\"Contacts\":{" + "\"records\":[" + "{"
-                                                                          + "\"Email\":\"sample@salesforce.com\"," + "\"LastName\":\"Smith\"," + "\"Title\":\"President\","
-                                                                          + "\"attributes\":{" + "\"referenceId\":\"ref2\"," + "\"type\":\"Contact\"" + "}" + "}," + "{"
-                                                                          + "\"Email\":\"sample@salesforce.com\"," + "\"LastName\":\"Evans\"," + "\"Title\":\"Vice President\","
-                                                                          + "\"attributes\":{" + "\"referenceId\":\"ref3\"," + "\"type\":\"Contact\"" + "}" + "}" + "]" + "}" + "},"
-                                                                          + "{" + "\"Industry\":\"Banking\"," + "\"Name\":\"SampleAccount2\"," + "\"NumberOfEmployees\":100,"
-                                                                          + "\"Phone\":\"1234567890\"," + "\"Website\":\"www.salesforce2.com\"," + "\"attributes\":{"
-                                                                          + "\"referenceId\":\"ref4\"," + "\"type\":\"Account\"" + "}" + "}" + "]" + "}",
-                     json);
+        final String expected = "{" +
+                "\"records\":[" +
+                "{" +
+                "\"Industry\":\"Banking\"," +
+                "\"Name\":\"SampleAccount\"," +
+                "\"NumberOfEmployees\":100," +
+                "\"Phone\":\"1234567890\"," +
+                "\"Website\":\"www.salesforce.com\"," +
+                "\"attributes\":{" +
+                "\"referenceId\":\"ref1\"," +
+                "\"type\":\"Account\"," +
+                "\"url\":null" +
+                "}," +
+                "\"Contacts\":{" +
+                "\"records\":[" +
+                "{" +
+                "\"Email\":\"sample@salesforce.com\"," +
+                "\"LastName\":\"Smith\"," +
+                "\"Title\":\"President\"," +
+                "\"attributes\":{" +
+                "\"referenceId\":\"ref2\"," +
+                "\"type\":\"Contact\"," +
+                "\"url\":null" +
+                "}" +
+                "}," +
+                "{" +
+                "\"Email\":\"sample@salesforce.com\"," +
+                "\"LastName\":\"Evans\"," +
+                "\"Title\":\"Vice President\"," +
+                "\"attributes\":{" +
+                "\"referenceId\":\"ref3\"," +
+                "\"type\":\"Contact\"," +
+                "\"url\":null" +
+                "}" +
+                "}" +
+                "]" +
+                "}" +
+                "}," +
+                "{" +
+                "\"Industry\":\"Banking\"," +
+                "\"Name\":\"SampleAccount2\"," +
+                "\"NumberOfEmployees\":100," +
+                "\"Phone\":\"1234567890\"," +
+                "\"Website\":\"www.salesforce2.com\"," +
+                "\"attributes\":{" +
+                "\"referenceId\":\"ref4\"," +
+                "\"type\":\"Account\"," +
+                "\"url\":null" +
+                "}" +
+                "}" +
+                "]" +
+                "}";
+        assertEquals("Should serialize to JSON as in Salesforce example", expected, json);
     }
 
     @Test
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/Account.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/Account.java
index a7ae955..b388c34 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/Account.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/Account.java
@@ -25,7 +25,6 @@ import com.thoughtworks.xstream.annotations.XStreamConverter;
 
 import org.apache.camel.component.salesforce.api.PicklistEnumConverter;
 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.SObjectDescription;
 import org.apache.camel.component.salesforce.api.dto.SObjectDescriptionUrls;
 import org.apache.camel.component.salesforce.api.dto.SObjectField;
@@ -38,7 +37,6 @@ import org.apache.camel.component.salesforce.api.dto.SObjectField;
 public class Account extends AbstractDescribedSObjectBase {
 
     public Account() {
-        super();
         getAttributes().setType("Account");
     }
 
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/Contact.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/Contact.java
index 5dc1832..d3afdce 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/Contact.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/Contact.java
@@ -35,7 +35,6 @@ import java.util.List;
 public class Contact extends AbstractDescribedSObjectBase {
 
     public Contact() {
-        super();
         getAttributes().setType("Contact");
     }
 
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 36cec18..7395bbd 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
@@ -37,9 +37,7 @@ import java.util.List;
 public class Document extends AbstractDescribedSObjectBase {
 
     public Document() {
-        Attributes attributes = new Attributes();
-        attributes.setType("Document");
-        setAttributes(attributes);
+        getAttributes().setType("Document");
     }
 
     private static final SObjectDescription DESCRIPTION = createSObjectDescription();
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/StringMSPTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/StringMSPTest.java
index b2da85d..3c92c8f 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/StringMSPTest.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/StringMSPTest.java
@@ -50,7 +50,6 @@ public class StringMSPTest extends AbstractSObjectBase {
 
     @JsonProperty("MspField")
     @JsonSerialize(using = StringMultiSelectPicklistSerializer.class)
-    @JsonInclude(value = Include.ALWAYS)
     public java.lang.String[] getMspField() {
         return MspField;
     }
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/Task.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/Task.java
index 2b9aa22..a392c85 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/Task.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/dto/generated/Task.java
@@ -30,6 +30,11 @@ import org.apache.camel.component.salesforce.api.dto.AbstractSObjectBase;
 @XStreamAlias("Task")
 public class Task extends AbstractSObjectBase {
 
+    public Task() {
+        getAttributes().setType("Task");
+    }
+
+
     private ZonedDateTime ActivityDate;
 
     private String Description;
@@ -53,5 +58,18 @@ public class Task extends AbstractSObjectBase {
     public void setDescription(final String description) {
         Description = description;
     }
+
+    @XStreamAlias("What")
+    private AbstractSObjectBase What;
+
+    @JsonProperty("What")
+    public AbstractSObjectBase getWhat() {
+        return this.What;
+    }
+
+    @JsonProperty("What")
+    public void setWhat(AbstractSObjectBase What) {
+        this.What = What;
+    }
 }
 //CHECKSTYLE:ON
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessorTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessorTest.java
index f858df5..6de8f7c 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessorTest.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessorTest.java
@@ -30,7 +30,7 @@ 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.api.SalesforceException;
-import org.apache.camel.component.salesforce.api.dto.AbstractDTOBase;
+import org.apache.camel.component.salesforce.api.dto.AbstractSObjectBase;
 import org.apache.camel.component.salesforce.internal.OperationName;
 import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.camel.support.DefaultExchange;
@@ -42,7 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 
 public class JsonRestProcessorTest {
 
-    static class TestObject extends AbstractDTOBase {
+    static class TestObject extends AbstractSObjectBase {
 
         private ZonedDateTime creationDate;
 
@@ -66,8 +66,24 @@ public class JsonRestProcessorTest {
         final Message in = new DefaultMessage(new DefaultCamelContext());
         try (InputStream stream = jsonProcessor.getRequestStream(in, new TestObject()); InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
             final String json = IOUtils.toString(reader);
+            assertThat(json).isEqualTo("{\"attributes\":{\"referenceId\":null,\"type\":null,\"url\":null}}");
+        }
+    }
+
+    @Test
+    public void shouldSerializeNullValues() throws SalesforceException, IOException {
+        final SalesforceComponent salesforce = new SalesforceComponent();
+        final SalesforceEndpointConfig configuration = new SalesforceEndpointConfig();
+        final SalesforceEndpoint endpoint = new SalesforceEndpoint("", salesforce, configuration, OperationName.UPDATE_SOBJECT, "");
 
-            assertThat(json).isEqualTo("{}");
+        final JsonRestProcessor jsonProcessor = new JsonRestProcessor(endpoint);
+
+        final Message in = new DefaultMessage(new DefaultCamelContext());
+        TestObject testObject = new TestObject();
+        testObject.getFieldsToNull().add("creationDate");
+        try (InputStream stream = jsonProcessor.getRequestStream(in, testObject); InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
+            final String json = IOUtils.toString(reader);
+            assertThat(json).isEqualTo("{\"creationDate\":null,\"attributes\":{\"referenceId\":null,\"type\":null,\"url\":null}}");
         }
     }
 
@@ -86,41 +102,7 @@ public class JsonRestProcessorTest {
         exchange.getIn().setBody(doc);
         try (InputStream stream = jsonRestProcessor.getRequestStream(exchange); InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
             final String result = IOUtils.toString(reader);
-            assertThat(result.length()).isLessThanOrEqualTo(48);
-        }
-    }
-
-    @Test
-    public void shouldSerializeNullValuesViaEndpointConfiguration() throws SalesforceException, IOException {
-        final SalesforceComponent salesforce = new SalesforceComponent();
-        final SalesforceEndpointConfig configuration = new SalesforceEndpointConfig();
-        configuration.setSerializeNulls(true);
-        final SalesforceEndpoint endpoint = new SalesforceEndpoint("", salesforce, configuration, OperationName.UPDATE_SOBJECT, "");
-
-        final JsonRestProcessor jsonProcessor = new JsonRestProcessor(endpoint);
-
-        final Message in = new DefaultMessage(new DefaultCamelContext());
-        try (InputStream stream = jsonProcessor.getRequestStream(in, new TestObject()); InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
-            final String json = IOUtils.toString(reader);
-
-            assertThat(json).isEqualTo("{\"creationDate\":null}");
-        }
-    }
-
-    @Test
-    public void shouldSerializeNullValuesViaHeaderConfiguration() throws SalesforceException, IOException {
-        final SalesforceComponent salesforce = new SalesforceComponent();
-        final SalesforceEndpointConfig configuration = new SalesforceEndpointConfig();
-        final SalesforceEndpoint endpoint = new SalesforceEndpoint("", salesforce, configuration, OperationName.UPDATE_SOBJECT, "");
-
-        final JsonRestProcessor jsonProcessor = new JsonRestProcessor(endpoint);
-
-        final Message in = new DefaultMessage(new DefaultCamelContext());
-        in.setHeader(SalesforceEndpointConfig.SERIALIZE_NULLS, true);
-        try (InputStream stream = jsonProcessor.getRequestStream(in, new TestObject()); InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
-            final String json = IOUtils.toString(reader);
-
-            assertThat(json).isEqualTo("{\"creationDate\":null}");
+            assertThat(result.length()).isLessThanOrEqualTo(104);
         }
     }
 }
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/resources/org/apache/camel/component/salesforce/api/dto/composite_request_example.json b/components/camel-salesforce/camel-salesforce-component/src/test/resources/org/apache/camel/component/salesforce/api/dto/composite_request_example.json
index 892bb39..534a4e3 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/resources/org/apache/camel/component/salesforce/api/dto/composite_request_example.json
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/resources/org/apache/camel/component/salesforce/api/dto/composite_request_example.json
@@ -11,7 +11,9 @@
       "BillingState" : "California",
       "Industry" : "Technology",
       "attributes" : {
-        "type" : "Account"
+        "referenceId" : null,
+        "type" : "Account",
+        "url" : null
       }
     }
   }, {
@@ -22,7 +24,9 @@
       "LastName" : "John Doe",
       "Phone" : "1234567890",
       "attributes" : {
-        "type" : "Contact"
+        "referenceId" : null,
+        "type" : "Contact",
+        "url" : null
       }
     }
   }, {
@@ -33,7 +37,9 @@
       "account__c" : "001xx000003DIpcAAG",
       "contactId__c" : "@{NewContact.id}",
       "attributes" : {
-        "type" : "AccountContactJunction__c"
+        "referenceId" : null,
+        "type" : "AccountContactJunction__c",
+        "url" : null
       }
     }
   } ]
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/GenerateMojo.java b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/GenerateMojo.java
index 79f6b32..2322879 100644
--- a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/GenerateMojo.java
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/GenerateMojo.java
@@ -529,7 +529,6 @@ public class GenerateMojo extends AbstractSalesforceMojo {
         for (final Field field : AbstractSObjectBase.class.getDeclaredFields()) {
             baseFields.add(field.getName());
         }
-
         return baseFields;
     }
 
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-pojo.vm b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-pojo.vm
index 746b2eb..40cc915 100644
--- a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-pojo.vm
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/resources/sobject-pojo.vm
@@ -16,7 +16,7 @@
 ## ------------------------------------------------------------------------
 ## sobject-pojo.vm
 /*
- * Salesforce DTO generated by camel-salesforce-maven-plugin
+ * Salesforce DTO generated by camel-salesforce-maven-plugin.
  */
 package $packageName;
 
@@ -73,9 +73,7 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include;
 public class $desc.Name extends AbstractDescribedSObjectBase {
 
     public ${desc.Name}() {
-        Attributes attributes = new Attributes();
-        attributes.setType("$desc.Name");
-        setAttributes(attributes);
+        getAttributes().setType("$desc.Name");
     }
 
     private static final SObjectDescription DESCRIPTION = createSObjectDescription();
@@ -115,7 +113,6 @@ public class $desc.Name extends AbstractDescribedSObjectBase {
 #else
     @JsonSerialize(using = MultiSelectPicklistSerializer.class)
 #end
-    @JsonInclude(value = Include.ALWAYS)
 #end
     public $fieldType get$propertyName() {
         return this.$propertyName;
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoOutputTest.java b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoOutputTest.java
index eaf3e83..cc4270d 100644
--- a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoOutputTest.java
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/java/org/apache/camel/maven/CamelSalesforceMojoOutputTest.java
@@ -104,17 +104,21 @@ public class CamelSalesforceMojoOutputTest {
 
     @Parameters(name = "json = {0}, source = {2}")
     public static Iterable<Object[]> parameters() throws IOException {
-        return Arrays.asList(testCase(TEST_CASE_FILE, "Case.java"), testCase(TEST_CASE_FILE, "Case_PickListAccentMarkEnum.java"),
-                             testCase(TEST_CASE_FILE, "Case_PickListQuotationMarkEnum.java"), testCase(TEST_CASE_FILE, "Case_PickListSlashEnum.java"), //
-                             testCase(TEST_CASE_FILE, "QueryRecordsCase.java"), testCase(TEST_CALCULATED_FORMULA_FILE, "ComplexCalculatedFormula.java"),
-                             testCase(TEST_CALCULATED_FORMULA_FILE, "QueryRecordsComplexCalculatedFormula.java"), testCase("asset.json", "Asset.java"), //
-                             testCase("asset.json", mojo -> {
-                                 mojo.customTypes = new HashMap<>();
-                                 mojo.customTypes.put("date", "java.time.LocalDateTime");
-
-                                 mojo.setup();
-                             }, s -> "Asset_LocalDateTime.java", "Asset.java"), //
-                             testCase("with_reference.json", "With_Reference__c.java"));
+        return Arrays.asList(testCase(TEST_CASE_FILE, "Case.java"),
+                testCase(TEST_CASE_FILE, "Case_PickListAccentMarkEnum.java"),
+                testCase(TEST_CASE_FILE, "Case_PickListQuotationMarkEnum.java"),
+                testCase(TEST_CASE_FILE, "Case_PickListSlashEnum.java"), //
+                testCase(TEST_CASE_FILE, "QueryRecordsCase.java"),
+                testCase(TEST_CALCULATED_FORMULA_FILE, "ComplexCalculatedFormula.java"),
+                testCase(TEST_CALCULATED_FORMULA_FILE, "QueryRecordsComplexCalculatedFormula.java"),
+                testCase("asset.json", "Asset.java"), //
+                testCase("asset.json", mojo -> {
+                 mojo.customTypes = new HashMap<>();
+                 mojo.customTypes.put("date", "java.time.LocalDateTime");
+
+                 mojo.setup();
+                }, s -> "Asset_LocalDateTime.java", "Asset.java"),
+                testCase("with_reference.json", "With_Reference__c.java"));
     }
 
     static GenerateMojo createMojo() {
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/generated/Asset.java b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/generated/Asset.java
index 06292f9..e755620 100644
--- a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/generated/Asset.java
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/generated/Asset.java
@@ -1,5 +1,5 @@
 /*
- * Salesforce DTO generated by camel-salesforce-maven-plugin
+ * Salesforce DTO generated by camel-salesforce-maven-plugin.
  */
 package $packageName;
 
@@ -30,9 +30,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 public class Asset extends AbstractDescribedSObjectBase {
 
     public Asset() {
-        Attributes attributes = new Attributes();
-        attributes.setType("Asset");
-        setAttributes(attributes);
+        getAttributes().setType("Asset");
     }
 
     private static final SObjectDescription DESCRIPTION = createSObjectDescription();
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/generated/Asset_LocalDateTime.java b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/generated/Asset_LocalDateTime.java
index 2fb1018..42f2520 100644
--- a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/generated/Asset_LocalDateTime.java
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/generated/Asset_LocalDateTime.java
@@ -1,5 +1,5 @@
 /*
- * Salesforce DTO generated by camel-salesforce-maven-plugin
+ * Salesforce DTO generated by camel-salesforce-maven-plugin.
  */
 package $packageName;
 
@@ -30,9 +30,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 public class Asset extends AbstractDescribedSObjectBase {
 
     public Asset() {
-        Attributes attributes = new Attributes();
-        attributes.setType("Asset");
-        setAttributes(attributes);
+        getAttributes().setType("Asset");
     }
 
     private static final SObjectDescription DESCRIPTION = createSObjectDescription();
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/generated/Case.java b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/generated/Case.java
index f6d54a9..dd6f7a9 100644
--- a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/generated/Case.java
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/generated/Case.java
@@ -1,5 +1,5 @@
 /*
- * Salesforce DTO generated by camel-salesforce-maven-plugin
+ * Salesforce DTO generated by camel-salesforce-maven-plugin.
  */
 package $packageName;
 
@@ -32,9 +32,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 public class Case extends AbstractDescribedSObjectBase {
 
     public Case() {
-        Attributes attributes = new Attributes();
-        attributes.setType("Case");
-        setAttributes(attributes);
+        getAttributes().setType("Case");
     }
 
     private static final SObjectDescription DESCRIPTION = createSObjectDescription();
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/generated/ComplexCalculatedFormula.java b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/generated/ComplexCalculatedFormula.java
index 5f538fc..3fa5216 100644
--- a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/generated/ComplexCalculatedFormula.java
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/generated/ComplexCalculatedFormula.java
@@ -1,5 +1,5 @@
 /*
- * Salesforce DTO generated by camel-salesforce-maven-plugin
+ * Salesforce DTO generated by camel-salesforce-maven-plugin.
  */
 package $packageName;
 
@@ -30,9 +30,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 public class ComplexCalculatedFormula extends AbstractDescribedSObjectBase {
 
     public ComplexCalculatedFormula() {
-        Attributes attributes = new Attributes();
-        attributes.setType("ComplexCalculatedFormula");
-        setAttributes(attributes);
+        getAttributes().setType("ComplexCalculatedFormula");
     }
 
     private static final SObjectDescription DESCRIPTION = createSObjectDescription();
diff --git a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/generated/With_Reference__c.java b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/generated/With_Reference__c.java
index 66c7e37..9bff002 100644
--- a/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/generated/With_Reference__c.java
+++ b/components/camel-salesforce/camel-salesforce-maven-plugin/src/test/resources/generated/With_Reference__c.java
@@ -1,5 +1,5 @@
 /*
- * Salesforce DTO generated by camel-salesforce-maven-plugin
+ * Salesforce DTO generated by camel-salesforce-maven-plugin.
  */
 package $packageName;
 
@@ -30,9 +30,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
 public class With_Reference__c extends AbstractDescribedSObjectBase {
 
     public With_Reference__c() {
-        Attributes attributes = new Attributes();
-        attributes.setType("With_Reference__c");
-        setAttributes(attributes);
+        getAttributes().setType("With_Reference__c");
     }
 
     private static final SObjectDescription DESCRIPTION = createSObjectDescription();
diff --git a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/SalesforceEndpointBuilderFactory.java b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/SalesforceEndpointBuilderFactory.java
index e121d9f..b607f23 100644
--- a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/SalesforceEndpointBuilderFactory.java
+++ b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/SalesforceEndpointBuilderFactory.java
@@ -654,32 +654,6 @@ public interface SalesforceEndpointBuilderFactory {
             return this;
         }
         /**
-         * Should the NULL values of given DTO be serialized with empty (NULL)
-         * values. This affects only JSON data format.
-         * 
-         * The option is a: <code>boolean</code> type.
-         * 
-         * Group: common
-         */
-        default SalesforceEndpointConsumerBuilder serializeNulls(
-                boolean serializeNulls) {
-            doSetProperty("serializeNulls", serializeNulls);
-            return this;
-        }
-        /**
-         * Should the NULL values of given DTO be serialized with empty (NULL)
-         * values. This affects only JSON data format.
-         * 
-         * The option will be converted to a <code>boolean</code> type.
-         * 
-         * Group: common
-         */
-        default SalesforceEndpointConsumerBuilder serializeNulls(
-                String serializeNulls) {
-            doSetProperty("serializeNulls", serializeNulls);
-            return this;
-        }
-        /**
          * SObject blob field name.
          * 
          * The option is a: <code>java.lang.String</code> type.
@@ -1611,32 +1585,6 @@ public interface SalesforceEndpointBuilderFactory {
             return this;
         }
         /**
-         * Should the NULL values of given DTO be serialized with empty (NULL)
-         * values. This affects only JSON data format.
-         * 
-         * The option is a: <code>boolean</code> type.
-         * 
-         * Group: common
-         */
-        default SalesforceEndpointProducerBuilder serializeNulls(
-                boolean serializeNulls) {
-            doSetProperty("serializeNulls", serializeNulls);
-            return this;
-        }
-        /**
-         * Should the NULL values of given DTO be serialized with empty (NULL)
-         * values. This affects only JSON data format.
-         * 
-         * The option will be converted to a <code>boolean</code> type.
-         * 
-         * Group: common
-         */
-        default SalesforceEndpointProducerBuilder serializeNulls(
-                String serializeNulls) {
-            doSetProperty("serializeNulls", serializeNulls);
-            return this;
-        }
-        /**
          * SObject blob field name.
          * 
          * The option is a: <code>java.lang.String</code> type.
@@ -2481,30 +2429,6 @@ public interface SalesforceEndpointBuilderFactory {
             return this;
         }
         /**
-         * Should the NULL values of given DTO be serialized with empty (NULL)
-         * values. This affects only JSON data format.
-         * 
-         * The option is a: <code>boolean</code> type.
-         * 
-         * Group: common
-         */
-        default SalesforceEndpointBuilder serializeNulls(boolean serializeNulls) {
-            doSetProperty("serializeNulls", serializeNulls);
-            return this;
-        }
-        /**
-         * Should the NULL values of given DTO be serialized with empty (NULL)
-         * values. This affects only JSON data format.
-         * 
-         * The option will be converted to a <code>boolean</code> type.
-         * 
-         * Group: common
-         */
-        default SalesforceEndpointBuilder serializeNulls(String serializeNulls) {
-            doSetProperty("serializeNulls", serializeNulls);
-            return this;
-        }
-        /**
          * SObject blob field name.
          * 
          * The option is a: <code>java.lang.String</code> type.
diff --git a/platforms/spring-boot/components-starter/camel-salesforce-starter/src/main/java/org/apache/camel/component/salesforce/springboot/SalesforceComponentConfiguration.java b/platforms/spring-boot/components-starter/camel-salesforce-starter/src/main/java/org/apache/camel/component/salesforce/springboot/SalesforceComponentConfiguration.java
index f5e493f..616e39d 100644
--- a/platforms/spring-boot/components-starter/camel-salesforce-starter/src/main/java/org/apache/camel/component/salesforce/springboot/SalesforceComponentConfiguration.java
+++ b/platforms/spring-boot/components-starter/camel-salesforce-starter/src/main/java/org/apache/camel/component/salesforce/springboot/SalesforceComponentConfiguration.java
@@ -659,11 +659,6 @@ public class SalesforceComponentConfiguration
          */
         private String sObjectSearch;
         /**
-         * Should the NULL values of given DTO be serialized with empty (NULL)
-         * values. This affects only JSON data format.
-         */
-        private Boolean serializeNulls = false;
-        /**
          * APEX method name
          */
         private String apexMethod;
@@ -913,14 +908,6 @@ public class SalesforceComponentConfiguration
             this.sObjectSearch = sObjectSearch;
         }
 
-        public Boolean getSerializeNulls() {
-            return serializeNulls;
-        }
-
-        public void setSerializeNulls(Boolean serializeNulls) {
-            this.serializeNulls = serializeNulls;
-        }
-
         public String getApexMethod() {
             return apexMethod;
         }


Mime
View raw message