[[transformer]]
= Transformer

Message transformers play a very important role in enabling the loose-coupling of message producers and message consumers.
Rather than requiring every message-producing component to know what type is expected by the next consumer, you can add transformers between those components.
Generic transformers, such as one that converts a `String` to an XML Document, are also highly reusable.

For some systems, it may be best to provide a https://www.enterpriseintegrationpatterns.com/CanonicalDataModel.html[canonical data model], but Spring Integration's general philosophy is not to require any particular format.
Rather, for maximum flexibility, Spring Integration aims to provide the simplest possible model for extension.
As with the other endpoint types, the use of declarative configuration in XML or Java annotations enables simple POJOs to be adapted for the role of message transformers.
The rest of this chapter describes these configuration options.

NOTE: For the sake of maximizing flexibility, Spring does not require XML-based message payloads.
Nevertheless, the framework does provide some convenient transformers for dealing with XML-based payloads if that is indeed the right choice for your application.
For more information on those transformers, see xref:xml.adoc[XML Support - Dealing with XML Payloads].

[[configuring-a-transformer-with-java-and-other-dsls]]
== Configuring a Transformer with Java and other DSLs

For simple Java & Annotation configuration, the Spring bean POJO method must be marked with a `@Transformer` annotation and the framework calls it when messages are consumed from an input channel:

[source,java]
----
public class SomeService {

    @Transformer(inputChannel = "transformChannel", outputChannel = "nextServiceChannel")
    public OutputData exampleTransformer(InputData payload) {
        ...
    }

}
----

See more information in the xref:configuration/annotations.adoc[Annotation Support].

For Java, Groovy or Kotlin DSLs, the `.transform()` operator of an `IntegrationFlow` represents a transformer endpoint:

[tabs]
======
Java DSL::
+
[source, java, role="primary"]
----
@Bean
public IntegrationFlow someFlow() {
    return IntegrationFlow
             .from("transformChannel")
             .transform(someService, "exampleTransformer")
             .channel("nextServiceChannel")
             .get();
}
----

Kotlin DSL::
+
[source, kotlin, role="secondary"]
----
@Bean
fun someFlow() =
    integrationFlow("transformChannel") {
        transform(someService, "exampleTransformer")
        channel("nextServiceChannel")
    }
----

Groovy DSL::
+
[source, groovy, role="secondary"]
----
@Bean
someFlow() {
    integrationFlow 'transformChannel',
            {
                transform someService, 'exampleTransformer'
                channel 'nextServiceChannel'
            }
}
----
======

See more information about the DSLs in the respective chapters:

* xref:dsl.adoc#java-dsl[Java DSL]
* xref:kotlin-dsl.adoc[Kotlin DSL]
* xref:groovy-dsl.adoc[Groovy DSL]

[[transformer-namespace]]
== Configuring a Transformer with XML

The `<transformer>` element is used to create a message-transforming endpoint.
In addition to `input-channel` and `output-channel` attributes, it requires a `ref` attribute.
The `ref` may either point to an object that contains the `@Transformer` annotation on a single method (see xref:transformer.adoc#transformer-annotation[Configuring a Transformer with Annotations]), or it may be combined with an explicit method name value provided in the `method` attribute.

[source,xml]
----
<int:transformer id="testTransformer" ref="testTransformerBean" input-channel="inChannel"
             method="transform" output-channel="outChannel"/>
<beans:bean id="testTransformerBean" class="org.foo.TestTransformer" />
----

Using a `ref` attribute is generally recommended if the custom transformer handler implementation can be reused in other `<transformer>` definitions.
However, if the custom transformer handler implementation should be scoped to a single definition of the `<transformer>`, you can define an inner bean definition, as the following example shows:

[source,xml]
----
<int:transformer id="testTransformer" input-channel="inChannel" method="transform"
                output-channel="outChannel">
  <beans:bean class="org.foo.TestTransformer"/>
</transformer>
----

NOTE: Using both the `ref` attribute and an inner handler definition in the same `<transformer>` configuration is not allowed, as it creates an ambiguous condition and results in an exception being thrown.

IMPORTANT: If the `ref` attribute references a bean that extends `AbstractMessageProducingHandler` (such as transformers provided by the framework itself), the configuration is optimized by injecting the output channel into the handler directly.
In this case, each `ref` must be to a separate bean instance (or a `prototype`-scoped bean) or use the inner `<bean/>` configuration type.
If you inadvertently reference the same message handler from multiple beans, you get a configuration exception.

When using a POJO, the method that is used for transformation may expect either the `Message` type or the payload type of inbound messages.
It may also accept message header values either individually or as a full map by using the `@Header` and `@Headers` parameter annotations, respectively.
The return value of the method can be any type.
If the return value is itself a `Message`, that is passed along to the transformer's output channel.

As of Spring Integration 2.0, a message transformer's transformation method can no longer return `null`.
Returning `null` results in an exception, because a message transformer should always be expected to transform each source message into a valid target message.
In other words, a message transformer should not be used as a message filter, because there is a dedicated `<filter>` option for that.
However, if you do need this type of behavior (where a component might return `null` and that should not be considered an error), you could use a service activator.
Its `requires-reply` value is `false` by default, but that can be set to `true` in order to have exceptions thrown for `null` return values, as with the transformer.

[[transformers-and-spring-expression-language-spel]]
== Transformers and Spring Expression Language (SpEL)

Like routers, aggregators, and other components, as of Spring Integration 2.0, transformers can also benefit from https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#expressions[SpEL support] whenever transformation logic is relatively simple.
The following example shows how to use a SpEL expression:

[source,xml]
----
<int:transformer input-channel="inChannel"
	output-channel="outChannel"
	expression="payload.toUpperCase() + '- [' + T(System).currentTimeMillis() + ']'"/>
----

The preceding example transforms the payload without writing a custom transformer.
Our payload (assumed to be a `String`) is upper-cased, concatenated with the current timestamp, and has some formatting applied.

[[common-transformers]]
== Common Transformers

Spring Integration provides a few transformer implementations.

[[object-to-string-transformer]]
=== Object-to-String Transformer

Because it is fairly common to use the `toString()` representation of an `Object`, Spring Integration provides an `ObjectToStringTransformer` (see also the `Transformers` factory) where the output is a `Message` with a String `payload`.
That `String` is the result of invoking the `toString()` operation on the inbound Message's payload.
The following example shows how to declare an instance of the object-to-string transformer:

[tabs]
======
Java DSL::
+
[source, java, role="primary"]
----
@Bean
public IntegrationFlow someFlow() {
    return IntegrationFlow
             .from("in")
             .transform(Transformers.objectToString())
             .channel("out")
             .get();
}
----

Kotlin DSL::
+
[source, kotlin, role="secondary"]
----
@Bean
fun someFlow() =
    integrationFlow("in") {
        transform(Transformers.objectToString())
        channel("out")
    }
----

Groovy DSL::
+
[source, groovy, role="secondary"]
----
@Bean
someFlow() {
    integrationFlow 'in',
            {
                transform Transformers.objectToString()
                channel 'out'
            }
}
----

XML::
+
[source, xml, role="secondary"]
----
<int:object-to-string-transformer input-channel="in" output-channel="out"/>
----
======

A potential use for this transformer would be sending some arbitrary object to the 'outbound-channel-adapter' in the `file` namespace.
Whereas that channel adapter only supports `String`, byte-array, or `java.io.File` payloads by default, adding this transformer immediately before the adapter handles the necessary conversion.
That works fine as long as the result of the `toString()` call is what you want to be written to the file.
Otherwise, you can provide a custom POJO-based transformer by using the generic 'transformer' element shown previously.

TIP: When debugging, this transformer is not typically necessary, since the `logging-channel-adapter` is capable of logging the message payload.
See xref:channel/configuration.adoc#channel-wiretap[Wire Tap] for more detail.

The object-to-string transformer is very simple.
It invokes `toString()` on the inbound payload.
Since Spring Integration 3.0, there are two exceptions to this rule:

* If the payload is a `char[]`, it invokes `new String(payload)`.
* If the payload is a `byte[]`, it invokes `new String(payload, charset)`, where `charset` is UTF-8 by default.
The `charset` can be modified by supplying the charset attribute on the transformer.

For more sophistication (such as selection of the charset dynamically, at runtime), you can use a SpEL expression-based transformer instead, as the following example shows:

[tabs]
======
Java DSL::
+
[source, java, role="primary"]
----
@Bean
public IntegrationFlow someFlow() {
    return IntegrationFlow
             .from("in")
             .transform("new String(payload, headers['myCharset']")
             .channel("out")
             .get();
}
----

XML::
+
[source, xml, role="secondary"]
----
<int:transformer input-channel="in" output-channel="out"
       expression="new String(payload, headers['myCharset']" />
----
======

If you need to serialize an `Object` to a byte array or deserialize a byte array back into an `Object`, Spring Integration provides symmetrical serialization transformers.
These use standard Java serialization by default, but you can provide an implementation of Spring `Serializer` or `Deserializer` strategies by using the `serializer` and `deserializer` attributes, respectively.
See also the `Transformers` factory class.
The following example shows to use Spring's serializer and deserializer:

[tabs]
======
Java DSL::
+
[source, java, role="primary"]
----
@Bean
public IntegrationFlow someFlow() {
    return IntegrationFlow
             .from("objectsIn")
             .transform(Transformers.serializer())
             .channel("bytesOut")
             .channel("bytesIn")
             .transform(Transformers.deserializer("com.mycom.*", "com.yourcom.*"))
             .channel("objectsOut")
             .get();
}
----

XML::
+
[source, xml, role="secondary"]
----
<int:payload-serializing-transformer input-channel="objectsIn" output-channel="bytesOut"/>

<int:payload-deserializing-transformer input-channel="bytesIn" output-channel="objectsOut"
    allow-list="com.mycom.*,com.yourcom.*"/>
----
======

IMPORTANT: When deserializing data from untrusted sources, you should consider adding a `allow-list` of package and class patterns.
By default, all classes are deserialized.

[[object-to-map-and-map-to-object-transformers]]
=== `Object`-to-`Map` and `Map`-to-`Object` Transformers

Spring Integration also provides `Object`-to-`Map` and `Map`-to-`Object` transformers, which use the JSON to serialize and de-serialize the object graphs.
The object hierarchy is introspected to the most primitive types (`String`, `int`, and so on).
The path to this type is described with SpEL, which becomes the `key` in the transformed `Map`.
The primitive type becomes the value.

Consider the following example:

[source,java]
----
public class Parent{
    private Child child;
    private String name;
    // setters and getters are omitted
}

public class Child{
    private String name;
    private List<String> nickNames;
    // setters and getters are omitted
}
----

The two classes in the preceding example are transformed to the following `Map`:

[source]
----
{person.name=George, person.child.name=Jenna, person.child.nickNames[0]=Jen ...}
----

The JSON-based `Map` lets you describe the object structure without sharing the actual types, which lets you restore and rebuild the object graph into a differently typed object graph, as long as you maintain the structure.

For example, the preceding structure could be restored back to the following object graph by using the `Map`-to-`Object` transformer:

[source,java]
----
public class Father {
    private Kid child;
    private String name;
    // setters and getters are omitted
}

public class Kid {
    private String name;
    private List<String> nickNames;
    // setters and getters are omitted
}
----

If you need to create a "`structured`" map, you can provide the `flatten` attribute.
The default is 'true'.
If you set it to 'false', the structure is a `Map` of `Map` objects.

Consider the following example:

[source,java]
----
public class Parent {
	private Child child;
	private String name;
	// setters and getters are omitted
}

public class Child {
	private String name;
	private List<String> nickNames;
	// setters and getters are omitted
}
----

The two classes in the preceding example are transformed to the following `Map`:

[source]
----
{name=George, child={name=Jenna, nickNames=[Bimbo, ...]}}
----

To configure these transformers, Spring Integration provides respective XML component and Java DSL factory:

[tabs]
======
Java DSL::
+
[source, java, role="primary"]
----
@Bean
public IntegrationFlow someFlow() {
    return IntegrationFlow
             .from("directInput")
             .transform(Transformers.toMap())
             .channel("output")
             .get();
}
----

XML::
+
[source, xml, role="secondary"]
----
<int:object-to-map-transformer input-channel="directInput" output-channel="output"/>
----
======

You can also set the `flatten` attribute to false, as follows:

[tabs]
======
Java DSL::
+
[source, java, role="primary"]
----
@Bean
public IntegrationFlow someFlow() {
    return IntegrationFlow
             .from("directInput")
             .transform(Transformers.toMap(false))
             .channel("output")
             .get();
}
----

XML::
+
[source, xml, role="secondary"]
----
<int:object-to-map-transformer input-channel="directInput" output-channel="output" flatten="false"/>
----
======

Spring Integration provides XML namespace support for Map-to-Object and the Java DSL factory has the `fromMap()` method, as the following example shows:

[tabs]
======
Java DSL::
+
[source, java, role="primary"]
----
@Bean
public IntegrationFlow someFlow() {
    return IntegrationFlow
             .from("input")
             .transform(Transformers.fromMap(org.something.Person.class))
             .channel("output")
             .get();
}
----

XML::
+
[source, xml, role="secondary"]
----
<int:map-to-object-transformer input-channel="input"
                         output-channel="output"
                         type="org.something.Person"/>
----
======

Alternatively, you could use a `ref` attribute and a prototype-scoped bean, as the following example shows:

[tabs]
======
Java DSL::
+
[source, java, role="primary"]
----
@Bean
IntegrationFlow someFlow() {
    return IntegrationFlow
             .from("inputA")
             .transform(Transformers.fromMap("person"))
             .channel("outputA")
             .get();
}

@Bean
@Scope("prototype")
Person person() {
    return new Person();
}
----

XML::
+
[source, xml, role="secondary"]
----
<int:map-to-object-transformer input-channel="inputA"
                               output-channel="outputA"
                               ref="person"/>
<bean id="person" class="org.something.Person" scope="prototype"/>
----
======

NOTE: The 'ref' and 'type' attributes are mutually exclusive.
Also, if you use the 'ref' attribute, you must point to a 'prototype' scoped bean.
Otherwise, a `BeanCreationException` is thrown.

Starting with version 5.0, you can supply the `ObjectToMapTransformer` with a customized `JsonObjectMapper` -- for when you need special formats for dates or nulls for empty collections (and other uses).
See xref:transformer.adoc#json-transformers[JSON Transformers] for more information about `JsonObjectMapper` implementations.

[[stream-transformer]]
=== Stream Transformer

The `StreamTransformer` transforms `InputStream` payloads to a `byte[]`( or a `String` if a `charset` is provided).

The following example shows how to use the `stream-transformer` element in XML:

[tabs]
======
Java DSL::
+
[source, java, role="primary"]
----
@Bean
public IntegrationFlow someFlow() {
    return IntegrationFlow
             .from("input")
             .transform(Transformers.fromStream("UTF-8"))
             .channel("output")
             .get();
}
----

XML::
+
[source, xml, role="secondary"]
----
<int:stream-transformer input-channel="directInput" output-channel="output"/> <!-- byte[] -->

<int:stream-transformer id="withCharset" charset="UTF-8"
    input-channel="charsetChannel" output-channel="output"/> <!-- String -->
----
======

The following example shows how to use the `StreamTransformer` class and the `@Transformer` annotation to configure a stream transformer in Java:

[source, java]
----
@Bean
@Transformer(inputChannel = "stream", outputChannel = "data")
public StreamTransformer streamToBytes() {
    return new StreamTransformer(); // transforms to byte[]
}

@Bean
@Transformer(inputChannel = "stream", outputChannel = "data")
public StreamTransformer streamToString() {
    return new StreamTransformer("UTF-8"); // transforms to String
}
----

[[json-transformers]]
=== JSON Transformers

Spring Integration provides Object-to-JSON and JSON-to-Object transformers.
The following pair of examples show how to declare them in XML:

[source,xml]
----
<int:object-to-json-transformer input-channel="objectMapperInput"/>

<int:json-to-object-transformer input-channel="objectMapperInput"
    type="foo.MyDomainObject"/>
----

By default, the transformers in the preceding listing use a vanilla `JsonObjectMapper`.
It is based on an implementation from the classpath.
You can provide your own custom `JsonObjectMapper` implementation with appropriate options or based on a required library (such as GSON), as the following example shows:

[source,xml]
----
<int:json-to-object-transformer input-channel="objectMapperInput"
    type="something.MyDomainObject" object-mapper="customObjectMapper"/>
----

[NOTE]
====
Beginning with version 3.0, the `object-mapper` attribute references an instance of a new strategy interface: `JsonObjectMapper`.
This abstraction lets multiple implementations of JSON mappers be used.
Implementation that wraps https://github.com/FasterXML[Jackson 2] is provided, with the version being detected on the classpath.
The class is `Jackson2JsonObjectMapper`, respectively.
====

You may wish to consider using a `FactoryBean` or a factory method to create the `JsonObjectMapper` with the required characteristics.
The following example shows how to use such a factory:

[source,java]
----
public class ObjectMapperFactory {

    public static Jackson2JsonObjectMapper getMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
        return new Jackson2JsonObjectMapper(mapper);
    }
}
----

The following example shows how to do the same thing in XML:

[source,xml]
----
<bean id="customObjectMapper" class="something.ObjectMapperFactory"
            factory-method="getMapper"/>
----

[IMPORTANT]
====
Beginning with version 2.2, the `object-to-json-transformer` sets the `content-type` header to `application/json`, by default, if the input message does not already have that header.

If you wish to set the `content-type` header to some other value or explicitly overwrite any existing header with some value (including `application/json`), use the `content-type` attribute.
If you wish to suppress the setting of the header, set the `content-type` attribute to an empty string (`""`).
Doing so results in a message with no `content-type` header, unless such a header was present on the input message.
====

Beginning with version 3.0, the `ObjectToJsonTransformer` adds headers, reflecting the source type, to the message.
Similarly, the `JsonToObjectTransformer` can use those type headers when converting the JSON to an object.
These headers are mapped in the AMQP adapters so that they are entirely compatible with the Spring-AMQP https://docs.spring.io/spring-amqp/api/[`JsonMessageConverter`].

This enables the following flows to work without any special configuration:

* `...->amqp-outbound-adapter---->`
* `---->amqp-inbound-adapter->json-to-object-transformer->...`
+
Where the outbound adapter is configured with a `JsonMessageConverter` and the inbound adapter uses the default `SimpleMessageConverter`.

* `...->object-to-json-transformer->amqp-outbound-adapter---->`
* `---->amqp-inbound-adapter->...`
+
Where the outbound adapter is configured with a `SimpleMessageConverter` and the inbound adapter uses the default `JsonMessageConverter`.

* `...->object-to-json-transformer->amqp-outbound-adapter---->`
* `---->amqp-inbound-adapter->json-to-object-transformer->`
+
Where both adapters are configured with a `SimpleMessageConverter`.

NOTE: When using the headers to determine the type, you should not provide a `class` attribute, because it takes precedence over the headers.

In addition to JSON Transformers, Spring Integration provides a built-in `#jsonPath` SpEL function for use in expressions.
For more information see xref:spel.adoc[Spring Expression Language (SpEL)].

[[transformer-xpath-spel-function]]
Since version 3.0, Spring Integration also provides a built-in `#xpath` SpEL function for use in expressions.
For more information see xref:xml/xpath-spel-function.adoc[#xpath SpEL Function].

Beginning with version 4.0, the `ObjectToJsonTransformer` supports the `resultType` property, to specify the node JSON representation.
The result node tree representation depends on the implementation of the provided `JsonObjectMapper`.
By default, the `ObjectToJsonTransformer` uses a `Jackson2JsonObjectMapper` and delegates the conversion of the object to the node tree to the `ObjectMapper#valueToTree` method.
The node JSON representation provides efficiency for using the `JsonPropertyAccessor` when the downstream message flow uses SpEL expressions with access to the properties of the JSON data.
See xref:spel.adoc#spel-property-accessors[Property Accessors] for more information.

Beginning with version 5.1, the `resultType` can be configured as `BYTES` to produce a message with the `byte[]` payload for convenience when working with downstream handlers which operate with this data type.

Starting with version 5.2, the `JsonToObjectTransformer` can be configured with a `ResolvableType` to support generics during deserialization with the target JSON processor.
Also, this component now consults request message headers first for the presence of the `JsonHeaders.RESOLVABLE_TYPE` or `JsonHeaders.TYPE_ID` and falls back to the configured type otherwise.
The `ObjectToJsonTransformer` now also populates a `JsonHeaders.RESOLVABLE_TYPE` header based on the request message payload for any possible downstream scenarios.

Starting with version 5.2.6, the `JsonToObjectTransformer` can be supplied with a `valueTypeExpression` to resolve a `ResolvableType` for the payload to convert from JSON at runtime against the request message.
By default, it consults `JsonHeaders` in the request message.
If this expression returns `null` or `ResolvableType` building throws a `ClassNotFoundException`, the transformer falls back to the provided `targetType`.
This logic is present as an expression because `JsonHeaders` may not have real class values, but rather some type ids which have to be mapped to target classes according some external registry.

[[Avro-transformers]]
=== Apache Avro Transformers

Version 5.2 added simple transformers to transform to/from Apache Avro.

They are unsophisticated in that there is no schema registry; the transformers simply use the schema embedded in the `SpecificRecord` implementation generated from the Avro schema.

Messages sent to the `SimpleToAvroTransformer` must have a payload that implements `SpecificRecord`; the transformer can handle multiple types.
The `SimpleFromAvroTransformer` must be configured with a `SpecificRecord` class which is used as the default type to deserialize.
You can also specify a SpEL expression to determine the type to deserialize using the `setTypeExpression` method.
The default SpEL expression is `headers[avro_type]` (`AvroHeaders.TYPE`) which, by default, is populated by the `SimpleToAvroTransformer` with the fully qualified class name of the source class.
If the expression returns `null`, the `defaultType` is used.

The `SimpleToAvroTransformer` also has a `setTypeExpression` method.
This allows decoupling of the producer and consumer where the sender can set the header to some token representing the type and the consumer then maps that token to a type.

[[Protobuf-transformers]]
=== Protocol Buffers Transformers

Version 6.1 adds support for transforming from and to https://protobuf.dev/[Protocol Buffers] data content.

The `ToProtobufTransformer` transforms a `com.google.protobuf.Message` message payloads into native byte array or json text payloads.
The `application/x-protobuf` content type (used by default) produces byte array output payload.
If the content type is `application/json` add the `com.google.protobuf:protobuf-java-util` if found on the classpath, then the output is text json payload.
If the content type header is not set the `ToProtobufTransformer` defaults to `application/x-protobuf`.

The `FromProtobufTransformer` transforms byte array or text protobuf payload (depending on the content type) back into `com.google.protobuf.Message` instances.
The `FromProtobufTransformer` should specify either an expected class type explicitly (use the `setExpectedType` method) or use a SpEL expression to determine the type to deserialize using the `setExpectedTypeExpression` method.
The default SpEL expression is `headers[proto_type]` (`ProtoHeaders.TYPE`) which is populated by the `ToProtobufTransformer` with the fully qualified class name of the source `com.google.protobuf.Message` class.

For example, compiling the following IDL:

[source,proto]
----
syntax = "proto2";
package tutorial;

option java_multiple_files = true;
option java_package = "org.example";
option java_outer_classname = "MyProtos";

message MyMessageClass {
  optional string foo = 1;
  optional string bar = 2;
}
----

will generate a new `org.example.MyMessageClass` class.

Then use the:
[source,java]
----
// Transforms a MyMessageClass instance into a byte array.
ToProtobufTransformer toTransformer = new ToProtobufTransformer();

MyMessageClass test = MyMessageClass.newBuilder()
                                .setFoo("foo")
                                .setBar("bar")
                                .build();
// message1 payload is byte array protocol buffer wire format.
Message message1 = toTransformer.transform(new GenericMessage<>(test));

// Transforms a byte array payload into a MyMessageClass instance.
FromProtobufTransformer fromTransformer = new FromProtobufTransformer();

// message2 payload == test
Message message2 =  fromTransformer.transform(message1);

----

[[transformer-annotation]]
== Configuring a Transformer with Annotations

You can add the `@Transformer` annotation to methods that expect either the `Message` type or the message payload type.
The return value is handled in the exact same way as described earlier <<transformer-namespace,in the section describing the `<transformer>` element>>.
The following example shows how to use the `@Transformer` annotation to transform a `String` into an `Order`:

[source,java]
----
@Transformer
Order generateOrder(String productId) {
    return new Order(productId);
}
----

Transformer methods can also accept the `@Header` and `@Headers` annotations, as documented in `xref:configuration/annotations.adoc[Annotation Support]`.
The following examples shows how to use the `@Header` annotation:

[source,java]
----
@Transformer
Order generateOrder(String productId, @Header("customerName") String customer) {
    return new Order(productId, customer);
}
----

See also xref:handler-advice/advising-with-annotations.adoc[Advising Endpoints Using Annotations].

[[header-filter]]
== Header Filter

Sometimes, your transformation use case might be as simple as removing a few headers.
For such a use case, Spring Integration provides a header filter that lets you specify certain header names that should be removed from the output message (for example, removing headers for security reasons or a value that was needed only temporarily).
Basically, the header filter is the opposite  of the header enricher.
The latter is discussed in xref:content-enrichment.adoc#header-enricher[Header Enricher].
The following example defines a header filter:

[tabs]
======
Java DSL::
+
[source, java, role="primary"]
----
@Bean
public IntegrationFlow someFlow() {
    return IntegrationFlow
             .from("inputChannel")
             .headerFilter("lastName", "state")
             .channel("outputChannel")
             .get();
}
----

XML::
+
[source, xml, role="secondary"]
----
<int:header-filter input-channel="inputChannel"
		output-channel="outputChannel" header-names="lastName, state"/>
----
======

As you can see, configuration of a header filter is quite simple.
It is a typical endpoint with input and output channels and a `header-names` attribute.
That attribute accepts the names of the headers (delimited by commas if there are multiple) that need to be removed.
So, in the preceding example, the headers named 'lastName' and 'state' are not present on the outbound message.


[[codec-based-transformers]]
== Codec-Based Transformers

See xref:codec.adoc[Codec].
