You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2023/12/26 07:58:56 UTC

(camel) branch main updated: Unmarshal (#12592)

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

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


The following commit(s) were added to refs/heads/main by this push:
     new f6bf6eeb4b0 Unmarshal (#12592)
f6bf6eeb4b0 is described below

commit f6bf6eeb4b09d944e02e105769d6e6e494b1bd6c
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Dec 26 08:58:50 2023 +0100

    Unmarshal (#12592)
    
    CAMEL-14028: Allow DataFormats to unmarshal known data formats without first converting to bytes
---
 .../camel-asn1/src/main/docs/asn1-dataformat.adoc  |  9 ++--
 .../camel/dataformat/asn1/ASN1DataFormat.java      | 25 ++++-------
 .../camel/component/cbor/CBORDataFormat.java       | 39 ++++++++++++++++-
 .../apache/camel/dataformat/csv/CsvDataFormat.java |  7 +++-
 .../camel/dataformat/csv/CsvUnmarshaller.java      | 30 ++++++++-----
 .../component/fastjson/FastjsonDataFormat.java     | 29 +++++++++++--
 .../dataformat/flatpack/FlatpackDataFormat.java    | 18 +++++++-
 .../camel/component/grok/GrokDataFormat.java       | 22 ++++++++--
 .../camel/component/gson/GsonDataFormat.java       | 49 +++++++++++++++++-----
 .../camel/component/gson/GsonDataFormatTest.java   |  7 +---
 .../jackson/AbstractJacksonDataFormat.java         | 39 ++++++++++++++++-
 .../component/jacksonxml/JacksonXMLDataFormat.java | 38 ++++++++++++++++-
 .../camel/converter/jaxb/JaxbDataFormat.java       | 34 +++++++++++----
 .../camel/component/jsonapi/JsonApiDataFormat.java | 26 ++++++------
 .../camel/component/jsonb/JsonbDataFormat.java     | 40 ++++++++++++++----
 .../component/snakeyaml/SnakeYAMLDataFormat.java   | 20 +++++++--
 .../camel/dataformat/soap/SoapDataFormat.java      |  5 ++-
 .../main/java/org/apache/camel/spi/DataFormat.java | 28 +++++++++++++
 .../org/apache/camel/model/SplitDefinition.java    |  7 ++--
 .../transformer/DataFormatTransformer.java         |  4 +-
 .../rest/RestProducerBindingProcessorTest.java     |  4 +-
 .../camel/processor/SplitterSingleMapTest.java     |  6 +--
 .../camel/processor/converter/ConvertBodyTest.java |  4 --
 .../processor/converter/ConvertHeaderTest.java     |  4 --
 .../management/ManagedRouteNodePrefixIdTest.java   |  2 -
 .../support/processor/UnmarshalProcessor.java      |  4 +-
 .../ROOT/pages/camel-4x-upgrade-guide-4_4.adoc     |  3 ++
 27 files changed, 381 insertions(+), 122 deletions(-)

diff --git a/components/camel-asn1/src/main/docs/asn1-dataformat.adoc b/components/camel-asn1/src/main/docs/asn1-dataformat.adoc
index 5b24ef9022b..863b5789a33 100644
--- a/components/camel-asn1/src/main/docs/asn1-dataformat.adoc
+++ b/components/camel-asn1/src/main/docs/asn1-dataformat.adoc
@@ -11,7 +11,7 @@
 
 *Since Camel {since}*
 
-The ASN.1 Data Format Data Format [Intoduction to ASN.1](https://www.itu.int/en/ITU-T/asn1/Pages/introduction.aspx) is a Camel Frameworks's data format implementation based on Bouncy Castle's bcprov-jdk18on library and jASN.1's java compiler for the formal notation used for describing data transmitted by telecommunications protocols, regardless of language implementation and physical representation of these data, whatever the application, whether complex or very simple. Messages can be u [...]
+The ASN.1 Data Format Data Format [Introduction to ASN.1](https://www.itu.int/en/ITU-T/asn1/Pages/introduction.aspx) is a Camel Frameworks's data format implementation based on Bouncy Castle's bcprov-jdk18on library and jASN.1's java compiler for the formal notation used for describing data transmitted by telecommunications protocols, regardless of language implementation and physical representation of these data, whatever the application, whether complex or very simple. Messages can be  [...]
 
 == ASN.1 Data Format Options
 
@@ -36,7 +36,10 @@ In such example, note that you need to set `usingIterator=true`
 
 [source,java]
 -----------------------------------------------------------------------
-from("direct:unmarshal").unmarshal(asn1).split(bodyAs(Iterator.class)).streaming().to("mock:unmarshal");
+from("direct:unmarshal")
+    .unmarshal(asn1)
+    .split(bodyAs(Iterator.class)).streaming()
+        .to("mock:unmarshal");
 -----------------------------------------------------------------------
 
 In the last example we unmarshal BER file payload to plain old Java Objects using Split EIP. The reason for applying Split EIP is already mentioned in the previous example. Please note and keep in mind that reason. In such example we also need to set the fully qualified name of the class or <YourObject>.class reference through data format.
@@ -50,7 +53,7 @@ from("direct:unmarshaldsl")
          .unmarshal()
          .asn1("org.apache.camel.dataformat.asn1.model.testsmscbercdr.SmsCdr")
          .split(bodyAs(Iterator.class)).streaming()
-.to("mock:unmarshaldsl");
+            .to("mock:unmarshaldsl");
 -----------------------------------------------------------------------
 
 == Dependencies
diff --git a/components/camel-asn1/src/main/java/org/apache/camel/dataformat/asn1/ASN1DataFormat.java b/components/camel-asn1/src/main/java/org/apache/camel/dataformat/asn1/ASN1DataFormat.java
index 3d8630f2944..dd8f4614372 100644
--- a/components/camel-asn1/src/main/java/org/apache/camel/dataformat/asn1/ASN1DataFormat.java
+++ b/components/camel-asn1/src/main/java/org/apache/camel/dataformat/asn1/ASN1DataFormat.java
@@ -18,10 +18,8 @@ package org.apache.camel.dataformat.asn1;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
-import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 
 import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream;
@@ -37,6 +35,7 @@ import org.bouncycastle.asn1.ASN1Primitive;
 
 @Dataformat("asn1")
 public class ASN1DataFormat extends ServiceSupport implements DataFormat, DataFormatName {
+
     private boolean usingIterator;
     private Class<?> unmarshalType;
 
@@ -74,15 +73,15 @@ public class ASN1DataFormat extends ServiceSupport implements DataFormat, DataFo
             berOut = new ByteArrayInputStream(byteInput);
         }
         try {
-            IOHelper.copy(berOut, stream);
+            if (berOut != null) {
+                IOHelper.copy(berOut, stream);
+            }
         } finally {
             IOHelper.close(berOut, stream);
         }
     }
 
-    private void encodeGenericTypeObject(Exchange exchange, OutputStream stream)
-            throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
-            InvocationTargetException, IOException {
+    private void encodeGenericTypeObject(Exchange exchange, OutputStream stream) throws Exception {
         Class<?>[] paramOut = new Class<?>[1];
         paramOut[0] = OutputStream.class;
         try (ReverseByteArrayOutputStream berOut = new ReverseByteArrayOutputStream(IOHelper.DEFAULT_BUFFER_SIZE / 256, true)) {
@@ -92,8 +91,8 @@ public class ASN1DataFormat extends ServiceSupport implements DataFormat, DataFo
         }
     }
 
-    @SuppressWarnings({ "rawtypes", "unchecked" })
     @Override
+    @SuppressWarnings({ "rawtypes", "unchecked" })
     public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
         if (usingIterator) {
             if (unmarshalType != null) {
@@ -101,7 +100,7 @@ public class ASN1DataFormat extends ServiceSupport implements DataFormat, DataFo
             }
             return new ASN1MessageIterator(exchange, stream);
         } else {
-            ASN1Primitive asn1Record = null;
+            ASN1Primitive asn1Record;
             byte[] asn1Bytes;
             try (ASN1InputStream ais = new ASN1InputStream(stream);
                  ByteArrayOutputStream asn1Out = new ByteArrayOutputStream();) {
@@ -131,14 +130,4 @@ public class ASN1DataFormat extends ServiceSupport implements DataFormat, DataFo
         this.unmarshalType = unmarshalType;
     }
 
-    @Override
-    protected void doStart() throws Exception {
-        // no op
-    }
-
-    @Override
-    protected void doStop() throws Exception {
-        // no op
-    }
-
 }
diff --git a/components/camel-cbor/src/main/java/org/apache/camel/component/cbor/CBORDataFormat.java b/components/camel-cbor/src/main/java/org/apache/camel/component/cbor/CBORDataFormat.java
index 60bc27dbb59..9f547509567 100644
--- a/components/camel-cbor/src/main/java/org/apache/camel/component/cbor/CBORDataFormat.java
+++ b/components/camel-cbor/src/main/java/org/apache/camel/component/cbor/CBORDataFormat.java
@@ -16,8 +16,10 @@
  */
 package org.apache.camel.component.cbor;
 
+import java.io.File;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.Reader;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
@@ -28,14 +30,17 @@ import java.util.Set;
 import java.util.stream.Collectors;
 
 import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.MapperFeature;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectReader;
 import com.fasterxml.jackson.databind.SerializationFeature;
 import com.fasterxml.jackson.databind.type.CollectionType;
 import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.Exchange;
+import org.apache.camel.WrappedFile;
 import org.apache.camel.spi.DataFormat;
 import org.apache.camel.spi.DataFormatName;
 import org.apache.camel.spi.annotations.Dataformat;
@@ -88,6 +93,11 @@ public class CBORDataFormat extends ServiceSupport implements DataFormat, DataFo
 
     @Override
     public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
+        return unmarshal(exchange, (Object) stream);
+    }
+
+    @Override
+    public Object unmarshal(Exchange exchange, Object body) throws Exception {
         Class<?> clazz = unmarshalType;
         String type = null;
         if (allowUnmarshallType) {
@@ -99,12 +109,37 @@ public class CBORDataFormat extends ServiceSupport implements DataFormat, DataFo
         if (type != null) {
             clazz = exchange.getContext().getClassResolver().resolveMandatoryClass(type);
         }
+
+        ObjectReader reader;
         if (collectionType != null) {
             CollectionType collType = objectMapper.getTypeFactory().constructCollectionType(collectionType, clazz);
-            return this.objectMapper.readValue(stream, collType);
+            reader = this.objectMapper.readerFor(collType);
         } else {
-            return this.objectMapper.readValue(stream, clazz);
+            reader = this.objectMapper.readerFor(clazz);
         }
+
+        // unwrap file (such as from camel-file)
+        if (body instanceof WrappedFile<?>) {
+            body = ((WrappedFile<?>) body).getBody();
+        }
+        Object answer;
+        if (body instanceof String b) {
+            answer = reader.readValue(b);
+        } else if (body instanceof byte[] arr) {
+            answer = reader.readValue(arr);
+        } else if (body instanceof Reader r) {
+            answer = reader.readValue(r);
+        } else if (body instanceof File f) {
+            answer = reader.readValue(f);
+        } else if (body instanceof JsonNode n) {
+            answer = reader.readValue(n);
+        } else {
+            // fallback to input stream
+            InputStream is = exchange.getContext().getTypeConverter().mandatoryConvertTo(InputStream.class, exchange, body);
+            answer = reader.readValue(is);
+        }
+
+        return answer;
     }
 
     @Override
diff --git a/components/camel-csv/src/main/java/org/apache/camel/dataformat/csv/CsvDataFormat.java b/components/camel-csv/src/main/java/org/apache/camel/dataformat/csv/CsvDataFormat.java
index 3de23c32eca..9d400e7e6b1 100644
--- a/components/camel-csv/src/main/java/org/apache/camel/dataformat/csv/CsvDataFormat.java
+++ b/components/camel-csv/src/main/java/org/apache/camel/dataformat/csv/CsvDataFormat.java
@@ -92,7 +92,12 @@ public class CsvDataFormat extends ServiceSupport implements DataFormat, DataFor
 
     @Override
     public Object unmarshal(Exchange exchange, InputStream inputStream) throws Exception {
-        return unmarshaller.unmarshal(exchange, inputStream);
+        return unmarshal(exchange, (Object) inputStream);
+    }
+
+    @Override
+    public Object unmarshal(Exchange exchange, Object body) throws Exception {
+        return unmarshaller.unmarshal(exchange, body);
     }
 
     @Override
diff --git a/components/camel-csv/src/main/java/org/apache/camel/dataformat/csv/CsvUnmarshaller.java b/components/camel-csv/src/main/java/org/apache/camel/dataformat/csv/CsvUnmarshaller.java
index 060537730ca..6811ef71166 100644
--- a/components/camel-csv/src/main/java/org/apache/camel/dataformat/csv/CsvUnmarshaller.java
+++ b/components/camel-csv/src/main/java/org/apache/camel/dataformat/csv/CsvUnmarshaller.java
@@ -69,12 +69,12 @@ abstract class CsvUnmarshaller {
     /**
      * Unmarshal the CSV
      *
-     * @param  exchange    Exchange (used for accessing type converter)
-     * @param  inputStream Input CSV stream
-     * @return             Unmarshalled CSV
-     * @throws IOException if the stream cannot be read properly
+     * @param  exchange  Exchange (used for accessing type converter)
+     * @param  body      the input
+     * @return           Unmarshalled CSV
+     * @throws Exception if error during unmarshalling
      */
-    public abstract Object unmarshal(Exchange exchange, InputStream inputStream) throws IOException;
+    public abstract Object unmarshal(Exchange exchange, Object body) throws Exception;
 
     private static CsvRecordConverter<?> extractConverter(CsvDataFormat dataFormat) {
         if (dataFormat.getRecordConverter() != null) {
@@ -99,9 +99,15 @@ abstract class CsvUnmarshaller {
         }
 
         @Override
-        public Object unmarshal(Exchange exchange, InputStream inputStream) throws IOException {
+        public Object unmarshal(Exchange exchange, Object body) throws Exception {
+            Reader reader = exchange.getContext().getTypeConverter().tryConvertTo(Reader.class, exchange, body);
+            if (reader == null) {
+                // fallback to input stream
+                InputStream is = exchange.getContext().getTypeConverter().mandatoryConvertTo(InputStream.class, exchange, body);
+                reader = new InputStreamReader(is, ExchangeHelper.getCharsetName(exchange));
+            }
             CSVParser parser
-                    = new CSVParser(new InputStreamReader(inputStream, ExchangeHelper.getCharsetName(exchange)), format);
+                    = new CSVParser(reader, format);
             try {
                 if (dataFormat.isCaptureHeaderRecord()) {
                     exchange.getMessage().setHeader(CsvConstants.HEADER_RECORD, parser.getHeaderNames());
@@ -132,10 +138,14 @@ abstract class CsvUnmarshaller {
         }
 
         @Override
-        public Object unmarshal(Exchange exchange, InputStream inputStream) throws IOException {
-            Reader reader = null;
+        public Object unmarshal(Exchange exchange, Object body) throws Exception {
+            Reader reader = exchange.getContext().getTypeConverter().tryConvertTo(Reader.class, exchange, body);
+            if (reader == null) {
+                // fallback to input stream
+                InputStream is = exchange.getContext().getTypeConverter().mandatoryConvertTo(InputStream.class, exchange, body);
+                reader = new InputStreamReader(is, ExchangeHelper.getCharsetName(exchange));
+            }
             try {
-                reader = new InputStreamReader(inputStream, ExchangeHelper.getCharsetName(exchange));
                 CSVParser parser = new CSVParser(reader, format);
                 CsvIterator<?> answer = new CsvIterator<>(parser, converter);
                 // add to UoW, so we can close the iterator, so it can release any resources
diff --git a/components/camel-fastjson/src/main/java/org/apache/camel/component/fastjson/FastjsonDataFormat.java b/components/camel-fastjson/src/main/java/org/apache/camel/component/fastjson/FastjsonDataFormat.java
index eeb0053cab1..a21a9cb4c1b 100644
--- a/components/camel-fastjson/src/main/java/org/apache/camel/component/fastjson/FastjsonDataFormat.java
+++ b/components/camel-fastjson/src/main/java/org/apache/camel/component/fastjson/FastjsonDataFormat.java
@@ -109,11 +109,32 @@ public class FastjsonDataFormat extends ServiceSupport
     }
 
     @Override
-    public Object unmarshal(final Exchange exchange, final InputStream stream) throws Exception {
-        if (unmarshalGenericType == null) {
-            return JSON.parseObject(stream, config.getCharset(), unmarshalType, config.getFeatures());
+    public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
+        return unmarshal(exchange, (Object) stream);
+    }
+
+    @Override
+    public Object unmarshal(Exchange exchange, Object body) throws Exception {
+        if (body instanceof String str) {
+            if (unmarshalGenericType == null) {
+                return JSON.parseObject(str, unmarshalType, config.getFeatures());
+            } else {
+                return JSON.parseObject(str, unmarshalGenericType, config.getFeatures());
+            }
+        } else if (body instanceof byte[] arr) {
+            if (unmarshalGenericType == null) {
+                return JSON.parseObject(arr, unmarshalType, config.getFeatures());
+            } else {
+                return JSON.parseObject(arr, unmarshalGenericType, config.getFeatures());
+            }
         } else {
-            return JSON.parseObject(stream, config.getCharset(), unmarshalGenericType, config.getFeatures());
+            // fallback to input stream
+            InputStream is = exchange.getContext().getTypeConverter().mandatoryConvertTo(InputStream.class, exchange, body);
+            if (unmarshalGenericType == null) {
+                return JSON.parseObject(is, config.getCharset(), unmarshalType, config.getFeatures());
+            } else {
+                return JSON.parseObject(is, config.getCharset(), unmarshalGenericType, config.getFeatures());
+            }
         }
     }
 
diff --git a/components/camel-flatpack/src/main/java/org/apache/camel/dataformat/flatpack/FlatpackDataFormat.java b/components/camel-flatpack/src/main/java/org/apache/camel/dataformat/flatpack/FlatpackDataFormat.java
index c575e22cc34..1c9c09c07c9 100644
--- a/components/camel-flatpack/src/main/java/org/apache/camel/dataformat/flatpack/FlatpackDataFormat.java
+++ b/components/camel-flatpack/src/main/java/org/apache/camel/dataformat/flatpack/FlatpackDataFormat.java
@@ -22,6 +22,7 @@ import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.Reader;
+import java.io.StringReader;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -110,7 +111,22 @@ public class FlatpackDataFormat extends ServiceSupport implements DataFormat, Da
 
     @Override
     public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
-        InputStreamReader reader = new InputStreamReader(stream, ExchangeHelper.getCharsetName(exchange));
+        return unmarshal(exchange, (Object) stream);
+    }
+
+    @Override
+    public Object unmarshal(Exchange exchange, Object body) throws Exception {
+        Reader reader;
+        if (body instanceof Reader r) {
+            reader = r;
+        } else if (body instanceof String s) {
+            reader = new StringReader(s);
+        } else {
+            // fallback to input stream
+            InputStream is = exchange.getContext().getTypeConverter().mandatoryConvertTo(InputStream.class, exchange, body);
+            reader = new InputStreamReader(is, ExchangeHelper.getCharsetName(exchange));
+        }
+
         try {
             Parser parser = createParser(exchange, reader);
             DataSet dataSet = parser.parse();
diff --git a/components/camel-grok/src/main/java/org/apache/camel/component/grok/GrokDataFormat.java b/components/camel-grok/src/main/java/org/apache/camel/component/grok/GrokDataFormat.java
index fd0a4f8c196..8d47841e820 100644
--- a/components/camel-grok/src/main/java/org/apache/camel/component/grok/GrokDataFormat.java
+++ b/components/camel-grok/src/main/java/org/apache/camel/component/grok/GrokDataFormat.java
@@ -20,6 +20,8 @@ import java.io.BufferedReader;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
+import java.io.Reader;
+import java.io.StringReader;
 import java.nio.CharBuffer;
 import java.util.*;
 import java.util.stream.Stream;
@@ -131,17 +133,31 @@ public class GrokDataFormat extends ServiceSupport implements DataFormat, DataFo
 
     @Override
     public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
+        return unmarshal(exchange, (Object) stream);
+    }
+
+    @Override
+    public Object unmarshal(Exchange exchange, Object body) throws Exception {
         List<Map<String, Object>> result = new ArrayList<>();
 
-        InputStreamReader in = new InputStreamReader(stream, ExchangeHelper.getCharsetName(exchange));
-        try (Stream<String> lines = new BufferedReader(in).lines()) {
+        Reader reader = null;
+        if (body instanceof String s) {
+            reader = new StringReader(s);
+        } else if (body instanceof Reader r) {
+            reader = r;
+        } else {
+            // fallback to input stream
+            InputStream is = exchange.getContext().getTypeConverter().mandatoryConvertTo(InputStream.class, exchange, body);
+            reader = new InputStreamReader(is, ExchangeHelper.getCharsetName(exchange));
+        }
+
+        try (Stream<String> lines = new BufferedReader(reader).lines()) {
             lines.forEachOrdered(line -> processLine(line, result));
         }
 
         if (result.isEmpty()) {
             return null;
         }
-
         if (result.size() == 1) {
             return result.get(0);
         }
diff --git a/components/camel-gson/src/main/java/org/apache/camel/component/gson/GsonDataFormat.java b/components/camel-gson/src/main/java/org/apache/camel/component/gson/GsonDataFormat.java
index e35b04b3f99..294fd30e1b1 100644
--- a/components/camel-gson/src/main/java/org/apache/camel/component/gson/GsonDataFormat.java
+++ b/components/camel-gson/src/main/java/org/apache/camel/component/gson/GsonDataFormat.java
@@ -16,12 +16,12 @@
  */
 package org.apache.camel.component.gson;
 
-import java.io.BufferedReader;
 import java.io.BufferedWriter;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
+import java.io.Reader;
 import java.lang.reflect.Type;
 import java.util.Arrays;
 import java.util.List;
@@ -32,6 +32,7 @@ import com.google.gson.FieldNamingStrategy;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import com.google.gson.LongSerializationPolicy;
+import com.google.gson.stream.JsonReader;
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.Exchange;
@@ -152,17 +153,43 @@ public class GsonDataFormat extends ServiceSupport
 
     @Override
     public Object unmarshal(final Exchange exchange, final InputStream stream) throws Exception {
-        try (final InputStreamReader isr = new InputStreamReader(stream, ExchangeHelper.getCharsetName(exchange));
-             final BufferedReader reader = IOHelper.buffered(isr)) {
-
-            String type = exchange.getIn().getHeader(GsonConstants.UNMARSHAL_TYPE, String.class);
-            if (type != null) {
-                Class<?> clazz = exchange.getContext().getClassResolver().resolveMandatoryClass(type);
-                return gson.fromJson(reader, clazz);
-            } else if (unmarshalGenericType == null) {
-                return gson.fromJson(reader, unmarshalType);
+        return unmarshal(exchange, (Object) stream);
+    }
+
+    @Override
+    public Object unmarshal(Exchange exchange, Object body) throws Exception {
+        Class<?> clazz = unmarshalType;
+        String type = exchange.getIn().getHeader(GsonConstants.UNMARSHAL_TYPE, String.class);
+        if (type != null) {
+            clazz = exchange.getContext().getClassResolver().resolveMandatoryClass(type);
+        }
+
+        if (body instanceof String str) {
+            if (unmarshalGenericType == null) {
+                return gson.fromJson(str, clazz);
+            } else {
+                return gson.fromJson(str, unmarshalGenericType);
+            }
+        } else if (body instanceof Reader r) {
+            if (unmarshalGenericType == null) {
+                return gson.fromJson(r, clazz);
+            } else {
+                return gson.fromJson(r, unmarshalGenericType);
+            }
+        } else if (body instanceof JsonReader r) {
+            if (unmarshalGenericType == null) {
+                return gson.fromJson(r, clazz);
+            } else {
+                return gson.fromJson(r, unmarshalGenericType);
+            }
+        } else {
+            // fallback to input stream
+            InputStream is = exchange.getContext().getTypeConverter().mandatoryConvertTo(InputStream.class, exchange, body);
+            Reader r = new InputStreamReader(is);
+            if (unmarshalGenericType == null) {
+                return gson.fromJson(r, clazz);
             } else {
-                return gson.fromJson(reader, unmarshalGenericType);
+                return gson.fromJson(r, unmarshalGenericType);
             }
         }
     }
diff --git a/components/camel-gson/src/test/java/org/apache/camel/component/gson/GsonDataFormatTest.java b/components/camel-gson/src/test/java/org/apache/camel/component/gson/GsonDataFormatTest.java
index dfc17e89e0b..8aedcd8608a 100644
--- a/components/camel-gson/src/test/java/org/apache/camel/component/gson/GsonDataFormatTest.java
+++ b/components/camel-gson/src/test/java/org/apache/camel/component/gson/GsonDataFormatTest.java
@@ -16,8 +16,6 @@
  */
 package org.apache.camel.component.gson;
 
-import java.io.*;
-import java.nio.charset.StandardCharsets;
 import java.util.*;
 
 import org.apache.camel.Exchange;
@@ -41,7 +39,6 @@ public class GsonDataFormatTest {
 
     @BeforeEach
     public void setup() {
-        when(message.getHeader(Exchange.CHARSET_NAME, String.class)).thenReturn(StandardCharsets.UTF_8.name());
         when(exchange.getIn()).thenReturn(message);
     }
 
@@ -64,9 +61,7 @@ public class GsonDataFormatTest {
         Object unmarshalled;
         try (GsonDataFormat gsonDataFormat = new GsonDataFormat()) {
             gsonDataFormat.doStart();
-            try (InputStream in = new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8))) {
-                unmarshalled = gsonDataFormat.unmarshal(exchange, in);
-            }
+            unmarshalled = gsonDataFormat.unmarshal(exchange, json);
             assertEquals(expected, unmarshalled);
         }
     }
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 7bf41509fa0..848e56f4ddb 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
@@ -16,8 +16,10 @@
  */
 package org.apache.camel.component.jackson;
 
+import java.io.File;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.Reader;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
@@ -30,9 +32,11 @@ import java.util.TimeZone;
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.core.FormatSchema;
 import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.MapperFeature;
 import com.fasterxml.jackson.databind.Module;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectReader;
 import com.fasterxml.jackson.databind.PropertyNamingStrategies;
 import com.fasterxml.jackson.databind.PropertyNamingStrategy;
 import com.fasterxml.jackson.databind.SerializationFeature;
@@ -40,6 +44,7 @@ import com.fasterxml.jackson.databind.type.CollectionType;
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.Exchange;
+import org.apache.camel.WrappedFile;
 import org.apache.camel.spi.DataFormat;
 import org.apache.camel.spi.DataFormatContentTypeHeader;
 import org.apache.camel.spi.DataFormatName;
@@ -161,6 +166,11 @@ public abstract class AbstractJacksonDataFormat extends ServiceSupport
 
     @Override
     public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
+        return unmarshal(exchange, (Object) stream);
+    }
+
+    @Override
+    public Object unmarshal(Exchange exchange, Object body) throws Exception {
         FormatSchema schema = null;
         if (this.schemaResolver != null) {
             schema = this.schemaResolver.resolve(exchange);
@@ -177,12 +187,37 @@ public abstract class AbstractJacksonDataFormat extends ServiceSupport
         if (type != null) {
             clazz = exchange.getContext().getClassResolver().resolveMandatoryClass(type);
         }
+
+        ObjectReader reader;
         if (collectionType != null) {
             CollectionType collType = objectMapper.getTypeFactory().constructCollectionType(collectionType, clazz);
-            return this.objectMapper.readerFor(collType).with(schema).readValue(stream);
+            reader = this.objectMapper.readerFor(collType).with(schema);
         } else {
-            return this.objectMapper.reader(schema).readValue(stream, clazz);
+            reader = this.objectMapper.reader(schema).forType(clazz);
         }
+
+        // unwrap file (such as from camel-file)
+        if (body instanceof WrappedFile<?>) {
+            body = ((WrappedFile<?>) body).getBody();
+        }
+        Object answer;
+        if (body instanceof String b) {
+            answer = reader.readValue(b);
+        } else if (body instanceof byte[] arr) {
+            answer = reader.readValue(arr);
+        } else if (body instanceof Reader r) {
+            answer = reader.readValue(r);
+        } else if (body instanceof File f) {
+            answer = reader.readValue(f);
+        } else if (body instanceof JsonNode n) {
+            answer = reader.readValue(n);
+        } else {
+            // fallback to input stream
+            InputStream is = exchange.getContext().getTypeConverter().mandatoryConvertTo(InputStream.class, exchange, body);
+            answer = reader.readValue(is);
+        }
+
+        return answer;
     }
 
     // Properties
diff --git a/components/camel-jacksonxml/src/main/java/org/apache/camel/component/jacksonxml/JacksonXMLDataFormat.java b/components/camel-jacksonxml/src/main/java/org/apache/camel/component/jacksonxml/JacksonXMLDataFormat.java
index 18192f32afb..4ec59b5bf8f 100644
--- a/components/camel-jacksonxml/src/main/java/org/apache/camel/component/jacksonxml/JacksonXMLDataFormat.java
+++ b/components/camel-jacksonxml/src/main/java/org/apache/camel/component/jacksonxml/JacksonXMLDataFormat.java
@@ -16,8 +16,10 @@
  */
 package org.apache.camel.component.jacksonxml;
 
+import java.io.File;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.Reader;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
@@ -28,8 +30,10 @@ import java.util.TimeZone;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.MapperFeature;
 import com.fasterxml.jackson.databind.Module;
+import com.fasterxml.jackson.databind.ObjectReader;
 import com.fasterxml.jackson.databind.SerializationFeature;
 import com.fasterxml.jackson.databind.type.CollectionType;
 import com.fasterxml.jackson.dataformat.xml.XmlMapper;
@@ -38,6 +42,7 @@ import com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationModu
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.Exchange;
+import org.apache.camel.WrappedFile;
 import org.apache.camel.spi.DataFormat;
 import org.apache.camel.spi.DataFormatContentTypeHeader;
 import org.apache.camel.spi.DataFormatName;
@@ -173,7 +178,11 @@ public class JacksonXMLDataFormat extends ServiceSupport
 
     @Override
     public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
+        return unmarshal(exchange, (Object) stream);
+    }
 
+    @Override
+    public Object unmarshal(Exchange exchange, Object body) throws Exception {
         // is there a header with the unmarshal type?
         Class<?> clazz = unmarshalType;
         String type = null;
@@ -186,12 +195,37 @@ public class JacksonXMLDataFormat extends ServiceSupport
         if (type != null) {
             clazz = exchange.getContext().getClassResolver().resolveMandatoryClass(type);
         }
+
+        ObjectReader reader;
         if (collectionType != null) {
             CollectionType collType = xmlMapper.getTypeFactory().constructCollectionType(collectionType, clazz);
-            return this.xmlMapper.readValue(stream, collType);
+            reader = this.xmlMapper.readerFor(collType);
+        } else {
+            reader = this.xmlMapper.reader().forType(clazz);
+        }
+
+        // unwrap file (such as from camel-file)
+        if (body instanceof WrappedFile<?>) {
+            body = ((WrappedFile<?>) body).getBody();
+        }
+        Object answer;
+        if (body instanceof String b) {
+            answer = reader.readValue(b);
+        } else if (body instanceof byte[] arr) {
+            answer = reader.readValue(arr);
+        } else if (body instanceof Reader r) {
+            answer = reader.readValue(r);
+        } else if (body instanceof File f) {
+            answer = reader.readValue(f);
+        } else if (body instanceof JsonNode n) {
+            answer = reader.readValue(n);
         } else {
-            return this.xmlMapper.readValue(stream, clazz);
+            // fallback to input stream
+            InputStream is = exchange.getContext().getTypeConverter().mandatoryConvertTo(InputStream.class, exchange, body);
+            answer = reader.readValue(is);
         }
+
+        return answer;
     }
 
     // Properties
diff --git a/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/JaxbDataFormat.java b/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/JaxbDataFormat.java
index dcb0e2c0db6..dbd845c19c6 100644
--- a/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/JaxbDataFormat.java
+++ b/components/camel-jaxb/src/main/java/org/apache/camel/converter/jaxb/JaxbDataFormat.java
@@ -21,7 +21,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
+import java.io.Reader;
 import java.lang.reflect.Method;
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -53,12 +53,12 @@ import org.apache.camel.CamelContextAware;
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePropertyKey;
 import org.apache.camel.InvalidPayloadException;
+import org.apache.camel.NoTypeConversionAvailableException;
 import org.apache.camel.TypeConverter;
 import org.apache.camel.spi.DataFormat;
 import org.apache.camel.spi.DataFormatContentTypeHeader;
 import org.apache.camel.spi.DataFormatName;
 import org.apache.camel.spi.annotations.Dataformat;
-import org.apache.camel.support.ExchangeHelper;
 import org.apache.camel.support.ResourceHelper;
 import org.apache.camel.support.service.ServiceSupport;
 import org.apache.camel.util.IOHelper;
@@ -271,16 +271,26 @@ public class JaxbDataFormat extends ServiceSupport
     }
 
     @Override
-    public Object unmarshal(Exchange exchange, InputStream stream) throws IOException {
+    public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
+        return unmarshal(exchange, (Object) stream);
+    }
+
+    @Override
+    public Object unmarshal(Exchange exchange, Object body) throws Exception {
         try {
             Object answer;
 
-            final XMLStreamReader xmlReader;
+            XMLStreamReader xmlReader;
             if (needFiltering(exchange)) {
                 xmlReader
-                        = typeConverter.convertTo(XMLStreamReader.class, exchange, createNonXmlFilterReader(exchange, stream));
+                        = typeConverter.convertTo(XMLStreamReader.class, exchange, createNonXmlFilterReader(exchange, body));
             } else {
-                xmlReader = typeConverter.convertTo(XMLStreamReader.class, exchange, stream);
+                xmlReader = typeConverter.tryConvertTo(XMLStreamReader.class, exchange, body);
+                if (xmlReader == null) {
+                    // fallback to input stream
+                    InputStream is = getCamelContext().getTypeConverter().mandatoryConvertTo(InputStream.class, exchange, body);
+                    xmlReader = typeConverter.convertTo(XMLStreamReader.class, exchange, is);
+                }
             }
             String partClassFromHeader = exchange.getIn().getHeader(JaxbConstants.JAXB_PART_CLASS, String.class);
             if (partClass != null || partClassFromHeader != null) {
@@ -306,9 +316,15 @@ public class JaxbDataFormat extends ServiceSupport
         }
     }
 
-    private NonXmlFilterReader createNonXmlFilterReader(Exchange exchange, InputStream stream)
-            throws UnsupportedEncodingException {
-        return new NonXmlFilterReader(new InputStreamReader(stream, ExchangeHelper.getCharsetName(exchange)));
+    private NonXmlFilterReader createNonXmlFilterReader(Exchange exchange, Object body)
+            throws NoTypeConversionAvailableException {
+        Reader reader = getCamelContext().getTypeConverter().tryConvertTo(Reader.class, exchange, body);
+        if (reader == null) {
+            // fallback to input stream
+            InputStream is = getCamelContext().getTypeConverter().mandatoryConvertTo(InputStream.class, exchange, body);
+            reader = new InputStreamReader(is);
+        }
+        return new NonXmlFilterReader(reader);
     }
 
     protected boolean needFiltering(Exchange exchange) {
diff --git a/components/camel-jsonapi/src/main/java/org/apache/camel/component/jsonapi/JsonApiDataFormat.java b/components/camel-jsonapi/src/main/java/org/apache/camel/component/jsonapi/JsonApiDataFormat.java
index 9231d129f98..b485601870b 100644
--- a/components/camel-jsonapi/src/main/java/org/apache/camel/component/jsonapi/JsonApiDataFormat.java
+++ b/components/camel-jsonapi/src/main/java/org/apache/camel/component/jsonapi/JsonApiDataFormat.java
@@ -80,9 +80,21 @@ public class JsonApiDataFormat extends ServiceSupport implements DataFormat, Dat
 
     @Override
     public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
+        return unmarshal(exchange, (Object) stream);
+    }
+
+    @Override
+    public Object unmarshal(Exchange exchange, Object body) throws Exception {
         ResourceConverter converter = new ResourceConverter(dataFormatTypeClasses);
-        JSONAPIDocument<?> jsonApiDocument = converter.readDocument(stream, mainFormatTypeClass);
-        return jsonApiDocument.get();
+
+        JSONAPIDocument<?> doc;
+        if (body instanceof byte[] arr) {
+            doc = converter.readDocument(arr, mainFormatTypeClass);
+        } else {
+            InputStream is = exchange.getContext().getTypeConverter().mandatoryConvertTo(InputStream.class, exchange, body);
+            doc = converter.readDocument(is, mainFormatTypeClass);
+        }
+        return doc.get();
     }
 
     public String getDataFormatTypes() {
@@ -144,14 +156,4 @@ public class JsonApiDataFormat extends ServiceSupport implements DataFormat, Dat
         }
     }
 
-    @Override
-    protected void doStart() throws Exception {
-        // noop
-    }
-
-    @Override
-    protected void doStop() throws Exception {
-        // noop
-    }
-
 }
diff --git a/components/camel-jsonb/src/main/java/org/apache/camel/component/jsonb/JsonbDataFormat.java b/components/camel-jsonb/src/main/java/org/apache/camel/component/jsonb/JsonbDataFormat.java
index 68c95860040..8386a19c4f2 100644
--- a/components/camel-jsonb/src/main/java/org/apache/camel/component/jsonb/JsonbDataFormat.java
+++ b/components/camel-jsonb/src/main/java/org/apache/camel/component/jsonb/JsonbDataFormat.java
@@ -18,6 +18,7 @@ package org.apache.camel.component.jsonb;
 
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.Reader;
 import java.lang.reflect.Type;
 
 import jakarta.json.bind.Jsonb;
@@ -40,7 +41,7 @@ import org.apache.camel.support.service.ServiceSupport;
  * Marshal POJOs to JSON and back using JSON-B.
  */
 @Dataformat("jsonb")
-@Metadata(includeProperties = "unmarshalTypeName,unmarshalType,objectMapper,prettyPrint,binaryStrategy,encoding,propertyOrder,propertyamingStrategy,skipNull")
+@Metadata(includeProperties = "unmarshalTypeName,unmarshalType,objectMapper,prettyPrint,binaryStrategy,encoding,propertyOrder,propertyNamingStrategy,skipNull")
 public class JsonbDataFormat extends ServiceSupport implements DataFormat, DataFormatName, CamelContextAware {
     private CamelContext camelContext;
     private Jsonb objectMapper;
@@ -51,7 +52,7 @@ public class JsonbDataFormat extends ServiceSupport implements DataFormat, DataF
     private String encoding = "UTF-8";
     private String binaryStrategy = BinaryDataStrategy.BASE_64;
     private String propertyOrder = PropertyOrderStrategy.ANY;
-    private String propertyamingStrategy = PropertyNamingStrategy.IDENTITY;
+    private String propertyNamingStrategy = PropertyNamingStrategy.IDENTITY;
     private boolean skipNull = true;
 
     public JsonbDataFormat() {
@@ -170,12 +171,12 @@ public class JsonbDataFormat extends ServiceSupport implements DataFormat, DataF
         this.propertyOrder = propertyOrder;
     }
 
-    public String getPropertyamingStrategy() {
-        return propertyamingStrategy;
+    public String getPropertyNamingStrategy() {
+        return propertyNamingStrategy;
     }
 
-    public void setPropertyamingStrategy(String propertyamingStrategy) {
-        this.propertyamingStrategy = propertyamingStrategy;
+    public void setPropertyNamingStrategy(String propertyNamingStrategy) {
+        this.propertyNamingStrategy = propertyNamingStrategy;
     }
 
     @Override
@@ -185,6 +186,11 @@ public class JsonbDataFormat extends ServiceSupport implements DataFormat, DataF
 
     @Override
     public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
+        return unmarshal(exchange, (Object) stream);
+    }
+
+    @Override
+    public Object unmarshal(Exchange exchange, Object body) throws Exception {
         // is there a header with the unmarshal type?
         Class<?> expectedType = unmarshalType;
         String type = exchange.getIn().getHeader("CamelJsonbUnmarshallType", String.class);
@@ -192,9 +198,25 @@ public class JsonbDataFormat extends ServiceSupport implements DataFormat, DataF
             expectedType = exchange.getContext().getClassResolver().resolveMandatoryClass(type);
         }
         if (expectedType == null && customType != null) {
-            return objectMapper.fromJson(stream, customType);
+            if (body instanceof String str) {
+                return objectMapper.fromJson(str, customType);
+            } else if (body instanceof Reader r) {
+                return objectMapper.fromJson(r, customType);
+            } else {
+                // fallback to input stream
+                InputStream is = exchange.getContext().getTypeConverter().mandatoryConvertTo(InputStream.class, exchange, body);
+                return objectMapper.fromJson(is, customType);
+            }
         } else {
-            return objectMapper.fromJson(stream, expectedType);
+            if (body instanceof String str) {
+                return objectMapper.fromJson(str, expectedType);
+            } else if (body instanceof Reader r) {
+                return objectMapper.fromJson(r, expectedType);
+            } else {
+                // fallback to input stream
+                InputStream is = exchange.getContext().getTypeConverter().mandatoryConvertTo(InputStream.class, exchange, body);
+                return objectMapper.fromJson(is, expectedType);
+            }
         }
     }
 
@@ -213,7 +235,7 @@ public class JsonbDataFormat extends ServiceSupport implements DataFormat, DataF
                     .withNullValues(!skipNull)
                     .withBinaryDataStrategy(binaryStrategy)
                     .withPropertyOrderStrategy(propertyOrder)
-                    .withPropertyNamingStrategy(propertyamingStrategy)
+                    .withPropertyNamingStrategy(propertyNamingStrategy)
                     .withEncoding(encoding));
         }
     }
diff --git a/components/camel-snakeyaml/src/main/java/org/apache/camel/component/snakeyaml/SnakeYAMLDataFormat.java b/components/camel-snakeyaml/src/main/java/org/apache/camel/component/snakeyaml/SnakeYAMLDataFormat.java
index e817d6a3fc3..78e53dd8668 100644
--- a/components/camel-snakeyaml/src/main/java/org/apache/camel/component/snakeyaml/SnakeYAMLDataFormat.java
+++ b/components/camel-snakeyaml/src/main/java/org/apache/camel/component/snakeyaml/SnakeYAMLDataFormat.java
@@ -20,6 +20,7 @@ import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
+import java.io.Reader;
 import java.lang.ref.WeakReference;
 import java.util.Arrays;
 import java.util.Collection;
@@ -118,9 +119,22 @@ public final class SnakeYAMLDataFormat extends ServiceSupport implements DataFor
 
     @Override
     public Object unmarshal(final Exchange exchange, final InputStream stream) throws Exception {
-        try (InputStreamReader isr = new InputStreamReader(stream, ExchangeHelper.getCharsetName(exchange))) {
-            Class<?> unmarshalObjectType = unmarshalType != null ? unmarshalType : Object.class;
-            return getYaml(exchange.getContext()).loadAs(isr, unmarshalObjectType);
+        return unmarshal(exchange, (Object) stream);
+    }
+
+    @Override
+    public Object unmarshal(Exchange exchange, Object body) throws Exception {
+        Class<?> unmarshalObjectType = unmarshalType != null ? unmarshalType : Object.class;
+
+        if (body instanceof String s) {
+            return getYaml(exchange.getContext()).loadAs(s, unmarshalObjectType);
+        } else if (body instanceof Reader r) {
+            return getYaml(exchange.getContext()).loadAs(r, unmarshalObjectType);
+        } else {
+            // fallback to InputStream
+            InputStream is = exchange.getContext().getTypeConverter().mandatoryConvertTo(InputStream.class, exchange, body);
+            Reader r = new InputStreamReader(is, ExchangeHelper.getCharsetName(exchange));
+            return getYaml(exchange.getContext()).loadAs(r, unmarshalObjectType);
         }
     }
 
diff --git a/components/camel-soap/src/main/java/org/apache/camel/dataformat/soap/SoapDataFormat.java b/components/camel-soap/src/main/java/org/apache/camel/dataformat/soap/SoapDataFormat.java
index 9f300acb3ee..b64739ee0a8 100644
--- a/components/camel-soap/src/main/java/org/apache/camel/dataformat/soap/SoapDataFormat.java
+++ b/components/camel-soap/src/main/java/org/apache/camel/dataformat/soap/SoapDataFormat.java
@@ -158,7 +158,7 @@ public class SoapDataFormat extends JaxbDataFormat {
      * Unmarshal a given SOAP xml stream and return the content of the SOAP body
      */
     @Override
-    public Object unmarshal(Exchange exchange, InputStream stream) throws IOException {
+    public Object unmarshal(Exchange exchange, Object body) throws Exception {
         String soapAction = getSoapActionFromExchange(exchange);
 
         // Determine the method name for an eventual BeanProcessor in the route
@@ -174,9 +174,10 @@ public class SoapDataFormat extends JaxbDataFormat {
             exchange.setProperty(Exchange.SOAP_ACTION, soapAction);
         }
 
-        Object unmarshalledObject = super.unmarshal(exchange, stream);
+        Object unmarshalledObject = super.unmarshal(exchange, body);
         Object rootObject = JAXBIntrospector.getValue(unmarshalledObject);
 
+        InputStream stream = exchange.getContext().getTypeConverter().mandatoryConvertTo(InputStream.class, exchange, body);
         return adapter.doUnmarshal(exchange, stream, rootObject);
     }
 
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 78ddc9ab059..c461b8ad97e 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
@@ -52,6 +52,34 @@ public interface DataFormat extends Service {
      * @param  stream    the input stream with the object to be unmarshalled
      * @return           the unmarshalled object
      * @throws Exception can be thrown
+     * @see              #unmarshal(Exchange, Object)
      */
     Object unmarshal(Exchange exchange, InputStream stream) throws Exception;
+
+    /**
+     * Unmarshals the given body into an object.
+     * <p/>
+     * <b>Notice:</b> The result is set as body on the exchange OUT message. It is possible to mutate the OUT message
+     * provided in the given exchange parameter. For instance adding headers to the OUT message will be preserved.
+     * <p/>
+     * It's also legal to return the <b>same</b> passed <tt>exchange</tt> as is but also a {@link Message} object as
+     * well which will be used as the OUT message of <tt>exchange</tt>.
+     * <p/>
+     * This method can be used when a dataformat is optimized to handle any kind of message body as-is. For example
+     * camel-jaxb has been optimized to do this. The regular {@link #unmarshal(Exchange, InputStream)} method requires
+     * Camel to convert the message body into an {@link InputStream} prior to calling the unmarshal method. This can be
+     * avoided if the data-format implementation can be optimized to handle this by itself, such as camel-jaxb that can
+     * handle message body as a String payload out of the box. When a data format implementation is using this method,
+     * then the {@link #unmarshal(Exchange, InputStream)} must also be implemented but should be empty, as Camel will
+     * not invoke this method.
+     *
+     * @param  exchange  the current exchange
+     * @param  body      the input object to be unmarshalled
+     * @return           the unmarshalled object
+     * @throws Exception can be thrown
+     */
+    default Object unmarshal(Exchange exchange, Object body) throws Exception {
+        InputStream is = exchange.getContext().getTypeConverter().mandatoryConvertTo(InputStream.class, exchange, body);
+        return unmarshal(exchange, is);
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/SplitDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/SplitDefinition.java
index de0b40653d2..a323920c93f 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/SplitDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/SplitDefinition.java
@@ -115,10 +115,9 @@ public class SplitDefinition extends OutputExpressionNode implements ExecutorSer
     // -------------------------------------------------------------------------
 
     /**
-     * Delimiter used in splitting messages.
-     * Can be turned off using the value <tt>false</tt>.
-     * To force not splitting then the delimiter can be set to <tt>single</tt> to use the value as a single list,
-     * this can be needed in some special situations.
+     * Delimiter used in splitting messages. Can be turned off using the value <tt>false</tt>. To force not splitting
+     * then the delimiter can be set to <tt>single</tt> to use the value as a single list, this can be needed in some
+     * special situations.
      * <p/>
      * The default value is comma.
      *
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DataFormatTransformer.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DataFormatTransformer.java
index 7e197d7c942..c58d156a59f 100644
--- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DataFormatTransformer.java
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DataFormatTransformer.java
@@ -16,8 +16,6 @@
  */
 package org.apache.camel.processor.transformer;
 
-import java.io.InputStream;
-
 import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
 import org.apache.camel.Message;
@@ -64,7 +62,7 @@ public class DataFormatTransformer extends Transformer {
         // Unmarshaling into Java Object
         if ((DataType.isAnyType(to) || to.isJavaType()) && (from.equals(getFrom()) || from.getScheme().equals(getName()))) {
             LOG.debug("Unmarshaling with: {}", dataFormat);
-            Object answer = dataFormat.unmarshal(exchange, message.getBody(InputStream.class));
+            Object answer = dataFormat.unmarshal(exchange, message.getBody());
             if (!DataType.isAnyType(to) && to.getName() != null) {
                 Class<?> toClass = context.getClassResolver().resolveClass(to.getName());
                 if (!toClass.isAssignableFrom(answer.getClass())) {
diff --git a/core/camel-core/src/test/java/org/apache/camel/component/rest/RestProducerBindingProcessorTest.java b/core/camel-core/src/test/java/org/apache/camel/component/rest/RestProducerBindingProcessorTest.java
index 4b6400bb25d..e6d345d5409 100644
--- a/core/camel-core/src/test/java/org/apache/camel/component/rest/RestProducerBindingProcessorTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/component/rest/RestProducerBindingProcessorTest.java
@@ -70,7 +70,7 @@ public class RestProducerBindingProcessorTest {
         exchange.setIn(input);
 
         final ResponsePojo response = new ResponsePojo();
-        when(outJsonDataFormat.unmarshal(same(exchange), any(InputStream.class))).thenReturn(response);
+        when(outJsonDataFormat.unmarshal(same(exchange), any(Object.class))).thenReturn(response);
 
         final ArgumentCaptor<AsyncCallback> bindingCallback = ArgumentCaptor.forClass(AsyncCallback.class);
 
@@ -105,7 +105,7 @@ public class RestProducerBindingProcessorTest {
         exchange.setIn(input);
 
         final ResponsePojo response = new ResponsePojo();
-        when(outXmlDataFormat.unmarshal(same(exchange), any(InputStream.class))).thenReturn(response);
+        when(outXmlDataFormat.unmarshal(same(exchange), any(Object.class))).thenReturn(response);
 
         final ArgumentCaptor<AsyncCallback> bindingCallback = ArgumentCaptor.forClass(AsyncCallback.class);
 
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/SplitterSingleMapTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/SplitterSingleMapTest.java
index ff12d7c2b55..a47b7434e84 100644
--- a/core/camel-core/src/test/java/org/apache/camel/processor/SplitterSingleMapTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/SplitterSingleMapTest.java
@@ -16,14 +16,14 @@
  */
 package org.apache.camel.processor;
 
+import java.util.LinkedHashMap;
+import java.util.Map;
+
 import org.apache.camel.ContextTestSupport;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.junit.jupiter.api.Test;
 
-import java.util.LinkedHashMap;
-import java.util.Map;
-
 public class SplitterSingleMapTest extends ContextTestSupport {
 
     @Test
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/converter/ConvertBodyTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/converter/ConvertBodyTest.java
index c7af7ffbd0c..af5f8745510 100644
--- a/core/camel-core/src/test/java/org/apache/camel/processor/converter/ConvertBodyTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/converter/ConvertBodyTest.java
@@ -33,10 +33,6 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.condition.DisabledOnOs;
 import org.junit.jupiter.api.condition.OS;
 
-import java.io.ByteArrayInputStream;
-import java.nio.charset.UnsupportedCharsetException;
-import java.util.Date;
-
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/converter/ConvertHeaderTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/converter/ConvertHeaderTest.java
index 799547701e3..c3a5be38fcc 100644
--- a/core/camel-core/src/test/java/org/apache/camel/processor/converter/ConvertHeaderTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/converter/ConvertHeaderTest.java
@@ -31,10 +31,6 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.condition.DisabledOnOs;
 import org.junit.jupiter.api.condition.OS;
 
-import java.io.ByteArrayInputStream;
-import java.nio.charset.UnsupportedCharsetException;
-import java.util.Date;
-
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
diff --git a/core/camel-management/src/test/java/org/apache/camel/management/ManagedRouteNodePrefixIdTest.java b/core/camel-management/src/test/java/org/apache/camel/management/ManagedRouteNodePrefixIdTest.java
index 2b65f1afd99..840524f5f82 100644
--- a/core/camel-management/src/test/java/org/apache/camel/management/ManagedRouteNodePrefixIdTest.java
+++ b/core/camel-management/src/test/java/org/apache/camel/management/ManagedRouteNodePrefixIdTest.java
@@ -42,8 +42,6 @@ public class ManagedRouteNodePrefixIdTest extends ManagementTestSupport {
         Set<ObjectName> set = mbeanServer.queryNames(new ObjectName("*:type=processors,*"), null);
         assertEquals(4, set.size());
 
-        System.out.println(set);
-
         // hardcoded ids should also be prefixed
         ManagedProcessorMBean mb
                 = context.getCamelContextExtension().getContextPlugin(ManagedCamelContext.class)
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 8b710a64bb0..25e2acba8ac 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
@@ -67,13 +67,13 @@ public class UnmarshalProcessor extends AsyncProcessorSupport implements Traceab
                 // The body is null, and it is an allowed value so let's skip the unmarshalling
                 out = exchange.getOut();
             } else {
-                stream = in.getMandatoryBody(InputStream.class);
+                Object body = in.getBody();
 
                 // lets set up the out message before we invoke the dataFormat so that it can mutate it if necessary
                 out = exchange.getOut();
                 out.copyFrom(in);
 
-                result = dataFormat.unmarshal(exchange, stream);
+                result = dataFormat.unmarshal(exchange, body);
             }
             if (result instanceof Exchange) {
                 if (result != exchange) {
diff --git a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_4.adoc b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_4.adoc
index dcf5ccbd528..01790c952ec 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_4.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_4.adoc
@@ -8,6 +8,9 @@ from both 4.0 to 4.1 and 4.1 to 4.2.
 
 === camel-core
 
+The `org.apache.camel.spi.DataFormat` has changed exception thrown from `IOException` to `Exception`
+in the unmarshal(Exchange exchange, InputStream stream)` method.
+
 Removed the deprecated constructor from the internal class `org.apache.camel.util.StopWatch`. Users of this class are advised to
 use the default constructor if necessary.