This version is still in development and is not considered stable yet.

Message and Headers

Message

A Message (package io.pipelite.spi.flow.exchange) is the container for the application payload - one for the input of the Exchange, and, once produced, one for its output. It carries the payload itself, its type and a correlation id, nothing else - it has no metadata of its own, that role belongs to Headers, which lives on the Exchange rather than on either Message (see below).

A Processor never needs to hold a Message reference directly: exchange.getInputPayload() / getInputPayloadAs(Class) read the input message’s payload, and exchange.setOutputPayload(Object) writes the output message’s payload - see Exchange.

Headers

Headers are string key-value pairs that live on the Exchange itself, not on the Message - there is a single set of headers per exchange, and neither its input nor its output Message knows anything about them.

Read

Headers headers = exchange.getHeaders();

// Optional read
Optional<String> value = headers.tryGetHeader("x-request-id");

// Read with expectation (throws NoSuchElementException if absent)
String value = headers.expectHeader("x-request-id");

// Typed read
Optional<Integer> n = headers.tryGetHeaderAs("retry-count", Integer.class);

// Presence check
boolean present = headers.hasHeader("x-request-id");

Write

headers.putHeader("x-correlation-id", "xyz-789");
headers.removeHeader("x-temp");

Headers survive across the whole flow: whenever an Exchange advances to the next node, the framework carries a copy of the current headers into the new Exchange - a header set at any step is still visible in every step downstream.

Headers vs. payload

Both travel through the flow together, but for different reasons:

  • Use headers for information about the message that a downstream step needs to decide what to do, without caring what the message actually contains - e.g. a priority or region header that a filter or toRoute(…​) uses to send an order down a different path depending on where it came from, regardless of what is inside the order itself. They are cheap to read (Headers['name']) and are exactly what filter and toRoute(…​) are built around (see Expressions).

  • Use the payload for the actual content being processed - e.g. the Order object itself, with its line items and total, that each Processor reads, transforms or replaces. It is what the pipeline exists to move and change; headers are metadata riding along with it, not a second place to put application data.

A simple test: if a value is something you would filter or route on without touching the business object, it belongs in a header; if it is the data your processors' logic actually reads or produces, it belongs in the payload.