Contents

marshal() converts a Java object in the exchange body to a serialized format (e.g., POJO → JSON string). unmarshal() converts a serialized format back to a Java object (e.g., JSON string → POJO).

DirectionDSL VerbExample
POJO → bytes/String.marshal()Java object → JSON / XML / CSV
bytes/String → POJO.unmarshal()JSON / XML / CSV → Java object

Add camel-jackson-starter. Use .marshal().json() to serialize a POJO to JSON and .unmarshal().json(MyClass.class) to deserialize.

<dependency> <groupId>org.apache.camel.springboot</groupId> <artifactId>camel-jackson-starter</artifactId> </dependency> import com.fasterxml.jackson.annotation.JsonProperty; import org.apache.camel.builder.RouteBuilder; import org.springframework.stereotype.Component; // Simple POJO record Order(String id, String product, int quantity) {} @Component public class JsonRoute extends RouteBuilder { @Override public void configure() { // POJO → JSON string from("direct:toJson") .marshal().json() .log("JSON: ${body}"); // JSON string → POJO from("direct:fromJson") .unmarshal().json(Order.class) .log("Order id: ${body.id}, product: ${body.product}"); // Full round-trip: receive JSON, deserialize, enrich, re-serialize from("direct:enrichOrder") .unmarshal().json(Order.class) .process(exchange -> { Order o = exchange.getMessage().getBody(Order.class); exchange.getMessage().setBody(new Order(o.id(), o.product(), o.quantity() * 2)); }) .marshal().json() .log("Enriched: ${body}"); } } By default, .unmarshal().json() without a type produces a Map<String, Object>. Pass the target class to get a typed POJO. For generic collections use unmarshal().json(new TypeReference<List<Order>>(){}).

Add camel-jaxb-starter. Annotate your class with @XmlRootElement and use .marshal().jaxb() / .unmarshal().jaxb().

<dependency> <groupId>org.apache.camel.springboot</groupId> <artifactId>camel-jaxb-starter</artifactId> </dependency> import jakarta.xml.bind.annotation.XmlRootElement; import jakarta.xml.bind.annotation.XmlElement; @XmlRootElement(name = "invoice") public class Invoice { @XmlElement public String invoiceId; @XmlElement public String customer; @XmlElement public double amount; public Invoice() {} public Invoice(String invoiceId, String customer, double amount) { this.invoiceId = invoiceId; this.customer = customer; this.amount = amount; } } import org.apache.camel.builder.RouteBuilder; import org.springframework.stereotype.Component; @Component public class XmlRoute extends RouteBuilder { @Override public void configure() { // POJO → XML string from("direct:toXml") .marshal().jaxb() .log("XML:\n${body}"); // XML string → POJO from("direct:fromXml") .unmarshal().jaxb(Invoice.class.getPackageName()) .log("Invoice id: ${body.invoiceId}"); } }

The jaxb() method accepts the package name where the ObjectFactory or @XmlRootElement classes live. Pass the class's package name string: Invoice.class.getPackageName().

Camel Bindy maps CSV rows to POJOs using field-level annotations. Add camel-bindy-starter and annotate your model class.

<dependency> <groupId>org.apache.camel.springboot</groupId> <artifactId>camel-bindy-starter</artifactId> </dependency> import org.apache.camel.dataformat.bindy.annotation.CsvRecord; import org.apache.camel.dataformat.bindy.annotation.DataField; @CsvRecord(separator = ",", skipFirstLine = true) // skip CSV header row public class ProductRow { @DataField(pos = 1) public String sku; @DataField(pos = 2) public String name; @DataField(pos = 3) public double price; @DataField(pos = 4) public int stock; } import org.apache.camel.builder.RouteBuilder; import org.apache.camel.dataformat.bindy.csv.BindyCsvDataFormat; import org.springframework.stereotype.Component; @Component public class CsvRoute extends RouteBuilder { @Override public void configure() { BindyCsvDataFormat csvFormat = new BindyCsvDataFormat(ProductRow.class); // CSV file → List<ProductRow> from("file:/tmp/csv-in?noop=true") .unmarshal(csvFormat) .split(body()) // split the List into individual rows .log("Product: ${body.sku} — ${body.name} @ ${body.price}") .to("direct:processProduct") .end(); // List<ProductRow> → CSV string from("direct:exportCsv") .marshal(csvFormat) .to("file:/tmp/csv-out?fileName=export.csv"); } } After unmarshal(csvFormat) the body is a List<Map<String, ProductRow>>. Use .split(body()) to iterate over each row individually. Bindy also supports fixed-width (@FixedLengthRecord) and key-value-pair formats.

Combine unmarshal and marshal in the same route to translate between formats. The POJO acts as the intermediate canonical model.

// Convert JSON payload → Java POJO → XML response from("direct:jsonToXml") .unmarshal().json(Order.class) // JSON → Order POJO .marshal().jaxb() // Order POJO → XML .setHeader(Exchange.CONTENT_TYPE, constant("application/xml")) .log("Converted to XML:\n${body}"); // Convert XML → POJO → JSON from("direct:xmlToJson") .unmarshal().jaxb(Invoice.class.getPackageName()) // XML → Invoice POJO .marshal().json() // Invoice POJO → JSON .log("Converted to JSON: ${body}");

Implement the DataFormat interface to create a custom format and register it in the Camel registry.

import org.apache.camel.Exchange; import org.apache.camel.spi.DataFormat; import org.apache.camel.support.service.ServiceSupport; import java.io.*; import java.nio.charset.StandardCharsets; public class UpperCaseFormat extends ServiceSupport implements DataFormat { @Override public void marshal(Exchange exchange, Object graph, OutputStream stream) throws Exception { String body = exchange.getContext().getTypeConverter() .convertTo(String.class, graph); stream.write(body.toUpperCase(java.util.Locale.ROOT) .getBytes(StandardCharsets.UTF_8)); } @Override public Object unmarshal(Exchange exchange, InputStream stream) throws Exception { return new String(stream.readAllBytes(), StandardCharsets.UTF_8).toLowerCase(); } } // Register and use the custom format UpperCaseFormat ucf = new UpperCaseFormat(); from("direct:custom") .marshal(ucf) .log("Upper: ${body}") .unmarshal(ucf) .log("Lower: ${body}");