You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by nf...@apache.org on 2022/03/01 16:16:12 UTC

[camel] branch CAMEL-17720/support-null-body-unmarshaller updated (56d830a -> fc313a3)

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

nfilotto pushed a change to branch CAMEL-17720/support-null-body-unmarshaller
in repository https://gitbox.apache.org/repos/asf/camel.git.


 discard 56d830a  CAMEL-17720: camel-jackson - Add option to allow jackson to support null body
     new fc313a3  CAMEL-17720: camel-jackson - Add option to allow jackson to support null body

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (56d830a)
            \
             N -- N -- N   refs/heads/CAMEL-17720/support-null-body-unmarshaller (fc313a3)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java | 6 ++++++
 .../camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json      | 3 +++
 .../camel-yaml-dsl/src/generated/resources/camelYamlDsl.json        | 3 +++
 3 files changed, 12 insertions(+)

[camel] 01/01: CAMEL-17720: camel-jackson - Add option to allow jackson to support null body

Posted by nf...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

nfilotto pushed a commit to branch CAMEL-17720/support-null-body-unmarshaller
in repository https://gitbox.apache.org/repos/asf/camel.git

commit fc313a39549e2c40de14271ddf9ab523494d12f3
Author: Nicolas Filotto <nf...@talend.com>
AuthorDate: Tue Mar 1 16:57:24 2022 +0100

    CAMEL-17720: camel-jackson - Add option to allow jackson to support null body
---
 .../jackson/JacksonDataFormatConfigurer.java       |  2 ++
 .../apache/camel/component/jackson/jackson.json    |  1 +
 .../src/main/docs/jackson-dataformat.adoc          |  4 +--
 .../jackson/AbstractJacksonDataFormat.java         | 14 ++++++++
 .../jackson/JacksonJsonDataFormatTest.java         |  2 ++
 .../component/jackson/JacksonMarshalTest.java      | 14 ++++++++
 .../component/jackson/JacksonObjectMapperTest.java |  4 +++
 .../jackson/SpringJacksonAllowNullBodyTest.java    | 42 ++++++++++++++++++++++
 .../jackson/SpringJacksonAllowNullBodyTest.xml     | 41 +++++++++++++++++++++
 .../main/java/org/apache/camel/spi/DataFormat.java |  9 +++++
 .../org/apache/camel/model/dataformat/json.json    |  3 +-
 .../org/apache/camel/builder/DataFormatClause.java | 35 ++++++++++++++++++
 .../camel/model/dataformat/JsonDataFormat.java     | 27 ++++++++++++--
 .../reifier/dataformat/JsonDataFormatReifier.java  |  1 +
 .../support/processor/UnmarshalProcessor.java      | 13 ++++---
 .../dsl/yaml/deserializers/ModelDeserializers.java |  6 ++++
 .../src/generated/resources/camel-yaml-dsl.json    |  3 ++
 .../src/generated/resources/camelYamlDsl.json      |  3 ++
 18 files changed, 214 insertions(+), 10 deletions(-)

diff --git a/components/camel-jackson/src/generated/java/org/apache/camel/component/jackson/JacksonDataFormatConfigurer.java b/components/camel-jackson/src/generated/java/org/apache/camel/component/jackson/JacksonDataFormatConfigurer.java
index 55ad712..08e7799 100644
--- a/components/camel-jackson/src/generated/java/org/apache/camel/component/jackson/JacksonDataFormatConfigurer.java
+++ b/components/camel-jackson/src/generated/java/org/apache/camel/component/jackson/JacksonDataFormatConfigurer.java
@@ -56,6 +56,8 @@ public class JacksonDataFormatConfigurer extends PropertyConfigurerSupport imple
         case "autoDiscoverSchemaResolver": dataformat.setAutoDiscoverSchemaResolver(property(camelContext, boolean.class, value)); return true;
         case "namingstrategy":
         case "namingStrategy": dataformat.setNamingStrategy(property(camelContext, java.lang.String.class, value)); return true;
+        case "allownullbody":
+        case "allowNullBody": dataformat.setAllowNullBody(property(camelContext, boolean.class, value)); return true;
         default: return false;
         }
     }
diff --git a/components/camel-jackson/src/generated/resources/org/apache/camel/component/jackson/jackson.json b/components/camel-jackson/src/generated/resources/org/apache/camel/component/jackson/jackson.json
index 1f6db8e..0e111ee 100644
--- a/components/camel-jackson/src/generated/resources/org/apache/camel/component/jackson/jackson.json
+++ b/components/camel-jackson/src/generated/resources/org/apache/camel/component/jackson/jackson.json
@@ -36,6 +36,7 @@
     "autoDiscoverSchemaResolver": { "kind": "attribute", "displayName": "Auto Discover Schema Resolver", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "When not disabled, the SchemaResolver will be looked up into the registry" },
     "namingStrategy": { "kind": "attribute", "displayName": "Naming Strategy", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "If set then Jackson will use the the defined Property Naming Strategy.Possible values are: LOWER_CAMEL_CASE, LOWER_DOT_CASE, LOWER_CASE, KEBAB_CASE, SNAKE_CASE and UPPER_CAMEL_CASE" },
     "contentTypeHeader": { "kind": "attribute", "displayName": "Content Type Header", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether the data format should set the Content-Type header with the type from the data format. For example application\/xml for data formats marshalling to XML, or application\/json for data formats marshalling to JSON" },
+    "allowNullBody": { "kind": "attribute", "displayName": "Allow Null Body", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Indicates whether null is allowed as value of a body to unmarshall." },
     "id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The id of this node" }
   }
 }
diff --git a/components/camel-jackson/src/main/docs/jackson-dataformat.adoc b/components/camel-jackson/src/main/docs/jackson-dataformat.adoc
index b4098f2..ca38878 100644
--- a/components/camel-jackson/src/main/docs/jackson-dataformat.adoc
+++ b/components/camel-jackson/src/main/docs/jackson-dataformat.adoc
@@ -32,7 +32,7 @@ include::partial$dataformat-options.adoc[]
 
 You can configure `JacksonDataFormat` to use a custom `ObjectMapper` in case you need more control of the mapping configuration.
 
-If you setup a single `ObjectMapper` in the registry, then Camel will automatic lookup and use this `ObjectMapper`.
+If you set up a single `ObjectMapper` in the registry, then Camel will automatic lookup and use this `ObjectMapper`.
 For example if you use Spring Boot, then Spring Boot can provide a default `ObjectMapper` for you if you have Spring MVC enabled.
 And this would allow Camel to detect that there is one bean of `ObjectMapper` class type in the Spring Boot bean registry
 and then use it. When this happens you should set a `INFO` logging from Camel.
@@ -56,7 +56,7 @@ getContext().getGlobalOptions().put("CamelJacksonTypeConverterToPojo", "true");
 
 The `camel-jackson` type converter integrates with xref:dataformats:jaxb-dataformat.adoc[JAXB]
 which means you can annotate POJO class with `JAXB` annotations that Jackson can use.
-You can also use Jacksons own annotations on your POJO classes.
+You can also use Jackson's annotations on your POJO classes.
 
 == Dependencies
 
diff --git a/components/camel-jackson/src/main/java/org/apache/camel/component/jackson/AbstractJacksonDataFormat.java b/components/camel-jackson/src/main/java/org/apache/camel/component/jackson/AbstractJacksonDataFormat.java
index b338ca9..dca218a 100644
--- a/components/camel-jackson/src/main/java/org/apache/camel/component/jackson/AbstractJacksonDataFormat.java
+++ b/components/camel-jackson/src/main/java/org/apache/camel/component/jackson/AbstractJacksonDataFormat.java
@@ -83,6 +83,7 @@ public abstract class AbstractJacksonDataFormat extends ServiceSupport
     private SchemaResolver schemaResolver;
     private boolean autoDiscoverSchemaResolver = true;
     private String namingStrategy;
+    private boolean allowNullBody;
 
     /**
      * Use the default Jackson {@link ObjectMapper} and {@link Object}
@@ -296,6 +297,19 @@ public abstract class AbstractJacksonDataFormat extends ServiceSupport
         this.namingStrategy = namingStrategy;
     }
 
+    @Override
+    public boolean allowNullBody() {
+        return isAllowNullBody();
+    }
+
+    public boolean isAllowNullBody() {
+        return allowNullBody;
+    }
+
+    public void setAllowNullBody(boolean allowNullBody) {
+        this.allowNullBody = allowNullBody;
+    }
+
     /**
      * To use custom Jackson {@link Module}s
      */
diff --git a/components/camel-jackson/src/test/java/org/apache/camel/component/jackson/JacksonJsonDataFormatTest.java b/components/camel-jackson/src/test/java/org/apache/camel/component/jackson/JacksonJsonDataFormatTest.java
index 09af454..9202598 100644
--- a/components/camel-jackson/src/test/java/org/apache/camel/component/jackson/JacksonJsonDataFormatTest.java
+++ b/components/camel-jackson/src/test/java/org/apache/camel/component/jackson/JacksonJsonDataFormatTest.java
@@ -35,6 +35,8 @@ public class JacksonJsonDataFormatTest extends JacksonMarshalTest {
 
                 from("direct:inPojo").marshal().json(JsonLibrary.Jackson);
                 from("direct:backPojo").unmarshal().json(JsonLibrary.Jackson, TestPojo.class).to("mock:reversePojo");
+
+                from("direct:nullBody").unmarshal().json(null, null, null, false, true).to("mock:nullBody");
             }
         };
     }
diff --git a/components/camel-jackson/src/test/java/org/apache/camel/component/jackson/JacksonMarshalTest.java b/components/camel-jackson/src/test/java/org/apache/camel/component/jackson/JacksonMarshalTest.java
index 55ba407..26d024b 100644
--- a/components/camel-jackson/src/test/java/org/apache/camel/component/jackson/JacksonMarshalTest.java
+++ b/components/camel-jackson/src/test/java/org/apache/camel/component/jackson/JacksonMarshalTest.java
@@ -86,6 +86,16 @@ public class JacksonMarshalTest extends CamelTestSupport {
         mock.assertIsSatisfied();
     }
 
+    @Test
+    public void testUnmarshalNullBody() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:nullBody");
+        mock.expectedMessageCount(1);
+        mock.message(0).body().isNull();
+
+        template.sendBody("direct:nullBody", null);
+        mock.assertIsSatisfied();
+    }
+
     @Override
     protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
@@ -107,6 +117,10 @@ public class JacksonMarshalTest extends CamelTestSupport {
 
                 from("direct:inPojo").marshal(formatPojo);
                 from("direct:backPojo").unmarshal(formatPojo).to("mock:reversePojo");
+
+                JacksonDataFormat allowNullBodyDataFormat = new JacksonDataFormat();
+                allowNullBodyDataFormat.setAllowNullBody(true);
+                from("direct:nullBody").unmarshal(allowNullBodyDataFormat).to("mock:nullBody");
             }
         };
     }
diff --git a/components/camel-jackson/src/test/java/org/apache/camel/component/jackson/JacksonObjectMapperTest.java b/components/camel-jackson/src/test/java/org/apache/camel/component/jackson/JacksonObjectMapperTest.java
index 6b6f55d..d6273cb 100644
--- a/components/camel-jackson/src/test/java/org/apache/camel/component/jackson/JacksonObjectMapperTest.java
+++ b/components/camel-jackson/src/test/java/org/apache/camel/component/jackson/JacksonObjectMapperTest.java
@@ -44,6 +44,10 @@ public class JacksonObjectMapperTest extends JacksonMarshalTest {
 
                 from("direct:inPojo").marshal(formatPojo);
                 from("direct:backPojo").unmarshal(formatPojo).to("mock:reversePojo");
+
+                JacksonDataFormat allowNullBodyDataFormat = new JacksonDataFormat();
+                allowNullBodyDataFormat.setAllowNullBody(true);
+                from("direct:nullBody").unmarshal(allowNullBodyDataFormat).to("mock:nullBody");
             }
         };
     }
diff --git a/components/camel-jackson/src/test/java/org/apache/camel/component/jackson/SpringJacksonAllowNullBodyTest.java b/components/camel-jackson/src/test/java/org/apache/camel/component/jackson/SpringJacksonAllowNullBodyTest.java
new file mode 100644
index 0000000..a666809
--- /dev/null
+++ b/components/camel-jackson/src/test/java/org/apache/camel/component/jackson/SpringJacksonAllowNullBodyTest.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.jackson;
+
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.spring.junit5.CamelSpringTestSupport;
+import org.junit.jupiter.api.Test;
+import org.springframework.context.support.AbstractXmlApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+public class SpringJacksonAllowNullBodyTest extends CamelSpringTestSupport {
+
+    @Test
+    public void testUnmarshalNullBody() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMessageCount(1);
+        mock.message(0).body().isNull();
+
+        template.sendBody("direct:in", null);
+        mock.assertIsSatisfied();
+    }
+
+    @Override
+    protected AbstractXmlApplicationContext createApplicationContext() {
+        return new ClassPathXmlApplicationContext("org/apache/camel/component/jackson/SpringJacksonAllowNullBodyTest.xml");
+    }
+
+}
diff --git a/components/camel-jackson/src/test/resources/org/apache/camel/component/jackson/SpringJacksonAllowNullBodyTest.xml b/components/camel-jackson/src/test/resources/org/apache/camel/component/jackson/SpringJacksonAllowNullBodyTest.xml
new file mode 100644
index 0000000..7ba55e3
--- /dev/null
+++ b/components/camel-jackson/src/test/resources/org/apache/camel/component/jackson/SpringJacksonAllowNullBodyTest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
+    ">
+
+  <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
+
+    <dataFormats>
+      <json id="jack" library="Jackson" allowNullBody="true"/>
+    </dataFormats>
+
+    <route>
+      <from uri="direct:in"/>
+      <unmarshal><custom ref="jack"/></unmarshal>
+      <to uri="mock:result"/>
+    </route>
+
+  </camelContext>
+
+</beans>
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/DataFormat.java b/core/camel-api/src/main/java/org/apache/camel/spi/DataFormat.java
index 78ddc9a..68f8a8c 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/DataFormat.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/DataFormat.java
@@ -54,4 +54,13 @@ public interface DataFormat extends Service {
      * @throws Exception can be thrown
      */
     Object unmarshal(Exchange exchange, InputStream stream) throws Exception;
+
+    /**
+     * Indicates whether {@code null} is allowed as value of a body to unmarshall.
+     *
+     * @return {@code true} if {@code null} is allowed, {@code false} otherwise.
+     */
+    default boolean allowNullBody() {
+        return false;
+    }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/dataformat/json.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/dataformat/json.json
index 15f6c07..caeec01 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/dataformat/json.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/dataformat/json.json
@@ -27,7 +27,7 @@
     "moduleRefs": { "kind": "attribute", "displayName": "Module Refs", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "To use custom Jackson modules referred from the Camel registry. Multiple modules can be separated by comma." },
     "enableFeatures": { "kind": "attribute", "displayName": "Enable Features", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Set of features to enable on the Jackson com.fasterxml.jackson.databind.ObjectMapper. The features should be a name that matches a enum from com.fasterxml.jackson.databind.SerializationFeature, com.fasterxml.jackson.databind.DeserializationFeature, or com.fasterxml.jack [...]
     "disableFeatures": { "kind": "attribute", "displayName": "Disable Features", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Set of features to disable on the Jackson com.fasterxml.jackson.databind.ObjectMapper. The features should be a name that matches a enum from com.fasterxml.jackson.databind.SerializationFeature, com.fasterxml.jackson.databind.DeserializationFeature, or com.fasterxml.j [...]
-    "permissions": { "kind": "attribute", "displayName": "Permissions", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Adds permissions that controls which Java packages and classes XStream is allowed to use during unmarshal from xml\/json to Java beans. A permission must be configured either here or globally using a JVM system property. The permission can be specified in  [...]
+    "permissions": { "kind": "attribute", "displayName": "Permissions", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Adds permissions that control which Java packages and classes XStream is allowed to use during unmarshal from xml\/json to Java beans. A permission must be configured either here or globally using a JVM system property. The permission can be specified in a [...]
     "allowUnmarshallType": { "kind": "attribute", "displayName": "Allow Unmarshall Type", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If enabled then Jackson is allowed to attempt to use the CamelJacksonUnmarshalType header during the unmarshalling. This should only be enabled when desired to be used." },
     "timezone": { "kind": "attribute", "displayName": "Timezone", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "If set then Jackson will use the Timezone when marshalling\/unmarshalling. This option will have no effect on the others Json DataFormat, like gson, fastjson and xstream." },
     "dropRootNode": { "kind": "attribute", "displayName": "Drop Root Node", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether XStream will drop the root node in the generated JSon. You may want to enable this when using POJOs; as then the written object will include the class name as root node, which is often not intended to be written in the JSON output." },
@@ -35,6 +35,7 @@
     "autoDiscoverSchemaResolver": { "kind": "attribute", "displayName": "Auto Discover Schema Resolver", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "When not disabled, the SchemaResolver will be looked up into the registry" },
     "namingStrategy": { "kind": "attribute", "displayName": "Naming Strategy", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "If set then Jackson will use the the defined Property Naming Strategy.Possible values are: LOWER_CAMEL_CASE, LOWER_DOT_CASE, LOWER_CASE, KEBAB_CASE, SNAKE_CASE and UPPER_CAMEL_CASE" },
     "contentTypeHeader": { "kind": "attribute", "displayName": "Content Type Header", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether the data format should set the Content-Type header with the type from the data format. For example application\/xml for data formats marshalling to XML, or application\/json for data formats marshalling to JSON" },
+    "allowNullBody": { "kind": "attribute", "displayName": "Allow Null Body", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Indicates whether null is allowed as value of a body to unmarshall." },
     "id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The id of this node" }
   }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/DataFormatClause.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/DataFormatClause.java
index 9707aa0b..50bbeb4 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/DataFormatClause.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/DataFormatClause.java
@@ -662,6 +662,22 @@ public class DataFormatClause<T extends ProcessorDefinition<?>> {
     }
 
     /**
+     * Uses the JSON data format
+     *
+     * @param type          the json type to use
+     * @param unmarshalType unmarshal type for json jackson type
+     * @param prettyPrint   turn pretty printing on or off
+     * @param allowNullBody allow or not {@code null} value as body to unmarshall
+     */
+    public T json(JsonLibrary type, Class<?> unmarshalType, boolean prettyPrint, boolean allowNullBody) {
+        JsonDataFormat json = new JsonDataFormat(type);
+        json.setUnmarshalType(unmarshalType);
+        json.setPrettyPrint(Boolean.toString(prettyPrint));
+        json.setAllowNullBody(Boolean.toString(allowNullBody));
+        return dataFormat(json);
+    }
+
+    /**
      * Uses the Jackson JSON data format
      *
      * @param unmarshalType unmarshal type for json jackson type
@@ -733,6 +749,25 @@ public class DataFormatClause<T extends ProcessorDefinition<?>> {
     }
 
     /**
+     * Uses the Jackson JSON data format
+     *
+     * @param unmarshalType unmarshal type for json jackson type
+     * @param jsonView      the view type for json jackson type
+     * @param include       include such as <tt>ALWAYS</tt>, <tt>NON_NULL</tt>, etc.
+     * @param prettyPrint   turn pretty printing on or off
+     * @param allowNullBody allow or not {@code null} value as body to unmarshall
+     */
+    public T json(Class<?> unmarshalType, Class<?> jsonView, String include, boolean prettyPrint, boolean allowNullBody) {
+        JsonDataFormat json = new JsonDataFormat(JsonLibrary.Jackson);
+        json.setUnmarshalType(unmarshalType);
+        json.setJsonView(jsonView);
+        json.setInclude(include);
+        json.setPrettyPrint(Boolean.toString(prettyPrint));
+        json.setAllowNullBody(Boolean.toString(allowNullBody));
+        return dataFormat(json);
+    }
+
+    /**
      * Uses the JSON API data format
      */
     public T jsonApi() {
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/dataformat/JsonDataFormat.java b/core/camel-core-model/src/main/java/org/apache/camel/model/dataformat/JsonDataFormat.java
index 289bb01..d740680 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/dataformat/JsonDataFormat.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/dataformat/JsonDataFormat.java
@@ -105,6 +105,9 @@ public class JsonDataFormat extends DataFormatDefinition implements ContentTypeH
               description = "Whether the data format should set the Content-Type header with the type from the data format."
                             + " For example application/xml for data formats marshalling to XML, or application/json for data formats marshalling to JSON")
     private String contentTypeHeader;
+    @XmlAttribute
+    @Metadata(javaType = "java.lang.Boolean", defaultValue = "false")
+    private String allowNullBody;
 
     public JsonDataFormat() {
         super("json");
@@ -339,7 +342,7 @@ public class JsonDataFormat extends DataFormatDefinition implements ContentTypeH
     }
 
     /**
-     * Adds permissions that controls which Java packages and classes XStream is allowed to use during unmarshal from
+     * Adds permissions that control which Java packages and classes XStream is allowed to use during unmarshal from
      * xml/json to Java beans.
      * <p/>
      * A permission must be configured either here or globally using a JVM system property. The permission can be
@@ -446,13 +449,24 @@ public class JsonDataFormat extends DataFormatDefinition implements ContentTypeH
     }
 
     /**
-     * If set then Jackson will use the the defined Property Naming Strategy. Possible values are: LOWER_CAMEL_CASE,
+     * If set then Jackson will use the defined Property Naming Strategy. Possible values are: LOWER_CAMEL_CASE,
      * LOWER_DOT_CASE, LOWER_CASE, KEBAB_CASE, SNAKE_CASE and UPPER_CAMEL_CASE
      */
     public void setNamingStrategy(String namingStrategy) {
         this.namingStrategy = namingStrategy;
     }
 
+    public String getAllowNullBody() {
+        return allowNullBody;
+    }
+
+    /**
+     * Indicates whether {@code null} is allowed as value of a body to unmarshall.
+     */
+    public void setAllowNullBody(String allowNullBody) {
+        this.allowNullBody = allowNullBody;
+    }
+
     //
     // Fluent builders
     //
@@ -471,6 +485,15 @@ public class JsonDataFormat extends DataFormatDefinition implements ContentTypeH
         return this;
     }
 
+    public JsonDataFormat allowNullBody(boolean allowNullBody) {
+        return allowNullBody(Boolean.toString(allowNullBody));
+    }
+
+    public JsonDataFormat allowNullBody(String allowNullBody) {
+        this.allowNullBody = allowNullBody;
+        return this;
+    }
+
     public JsonDataFormat prettyPrint(boolean prettyPrint) {
         return prettyPrint(Boolean.toString(prettyPrint));
     }
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/dataformat/JsonDataFormatReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/dataformat/JsonDataFormatReifier.java
index ed584fb..21e71fb 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/dataformat/JsonDataFormatReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/dataformat/JsonDataFormatReifier.java
@@ -31,6 +31,7 @@ public class JsonDataFormatReifier extends DataFormatReifier<JsonDataFormat> {
 
     @Override
     protected void prepareDataFormatConfig(Map<String, Object> properties) {
+        properties.put("allowNullBody", definition.getAllowNullBody());
         properties.put("objectMapper", asRef(definition.getObjectMapper()));
         if (definition.getLibrary() == JsonLibrary.Jackson) {
             if (definition.getUseDefaultObjectMapper() == null) {
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/processor/UnmarshalProcessor.java b/core/camel-support/src/main/java/org/apache/camel/support/processor/UnmarshalProcessor.java
index d05fccb..17317f6 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/processor/UnmarshalProcessor.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/processor/UnmarshalProcessor.java
@@ -55,13 +55,16 @@ public class UnmarshalProcessor extends AsyncProcessorSupport implements Traceab
         InputStream stream = null;
         Object result = null;
         try {
-            stream = exchange.getIn().getMandatoryBody(InputStream.class);
+            final Message in = exchange.getIn();
+            final Message out = exchange.getOut();
+            if (!dataFormat.allowNullBody() || in.getBody() != null) {
+                stream = in.getMandatoryBody(InputStream.class);
 
-            // lets setup the out message before we invoke the dataFormat so that it can mutate it if necessary
-            Message out = exchange.getOut();
-            out.copyFrom(exchange.getIn());
+                // let's set up the out message before we invoke the dataFormat so that it can mutate it if necessary
+                out.copyFrom(in);
 
-            result = dataFormat.unmarshal(exchange, stream);
+                result = dataFormat.unmarshal(exchange, stream);
+            }
             if (result instanceof Exchange) {
                 if (result != exchange) {
                     // it's not allowed to return another exchange other than the one provided to dataFormat
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
index 0f092a9..145fa9f 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
@@ -7363,6 +7363,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
             nodes = "json",
             properties = {
                     @YamlProperty(name = "allow-jms-type", type = "boolean"),
+                    @YamlProperty(name = "allow-null-body", type = "boolean"),
                     @YamlProperty(name = "allow-unmarshall-type", type = "boolean"),
                     @YamlProperty(name = "auto-discover-object-mapper", type = "boolean"),
                     @YamlProperty(name = "auto-discover-schema-resolver", type = "boolean"),
@@ -7407,6 +7408,11 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     target.setAllowJmsType(val);
                     break;
                 }
+                case "allow-null-body": {
+                    String val = asText(node);
+                    target.setAllowNullBody(val);
+                    break;
+                }
                 case "allow-unmarshall-type": {
                     String val = asText(node);
                     target.setAllowUnmarshallType(val);
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json
index 84fc726..90ac418 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json
@@ -5140,6 +5140,9 @@
           "allow-jms-type" : {
             "type" : "boolean"
           },
+          "allow-null-body" : {
+            "type" : "boolean"
+          },
           "allow-unmarshall-type" : {
             "type" : "boolean"
           },
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camelYamlDsl.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camelYamlDsl.json
index 417f99a..1bc2a0b 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camelYamlDsl.json
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camelYamlDsl.json
@@ -5041,6 +5041,9 @@
           "allowJmsType" : {
             "type" : "boolean"
           },
+          "allowNullBody" : {
+            "type" : "boolean"
+          },
           "allowUnmarshallType" : {
             "type" : "boolean"
           },