[[content-enricher]]
= Content Enricher

At times, you may have a requirement to enhance a request with more information than was provided by the target system.
The https://www.enterpriseintegrationpatterns.com/DataEnricher.html[data enricher] pattern describes various scenarios as well as the component (Enricher) that lets you address such requirements.

The Spring Integration `Core` module includes two enrichers:

* xref:content-enrichment.adoc#header-enricher[Header Enricher]
* xref:content-enrichment.adoc#payload-enricher[Payload Enricher]

It also includes three adapter-specific header enrichers:

* xref:xml/xpath-header-enricher.adoc[XPath Header Enricher (XML Module)]
* xref:mail.adoc#mail-namespace[Mail Header Enricher (Mail Module)]
* xref:xmpp.adoc#xmpp-message-outbound-channel-adapter[XMPP Header Enricher (XMPP Module)]

See the adapter-specific sections of this reference manual to learn more about those adapters.

For more information regarding expressions support, see xref:spel.adoc[Spring Expression Language (SpEL)].

[[header-enricher]]
== Header Enricher

If you need do nothing more than add headers to a message and the headers are not dynamically determined by the message content, referencing a custom implementation of a transformer may be overkill.
For that reason, Spring Integration provides support for the header enricher pattern.
It is exposed through the `<header-enricher>` element.
The following example shows how to use it:

[source,xml]
----
<int:header-enricher input-channel="in" output-channel="out">
    <int:header name="foo" value="123"/>
    <int:header name="bar" ref="someBean"/>
</int:header-enricher>
----

The header enricher also provides helpful sub-elements to set well known header names, as the following example shows:

[source,xml]
----
<int:header-enricher input-channel="in" output-channel="out">
    <int:error-channel ref="applicationErrorChannel"/>
    <int:reply-channel ref="quoteReplyChannel"/>
    <int:correlation-id value="123"/>
    <int:priority value="HIGHEST"/>
    <routing-slip value="channel1; routingSlipRoutingStrategy; request.headers[myRoutingSlipChannel]"/>
    <int:header name="bar" ref="someBean"/>
</int:header-enricher>
----

The preceding configuration shows that, for well known headers (such as `errorChannel`, `correlationId`, `priority`, `replyChannel`, `routing-slip`, and others), instead of using generic `<header>` sub-elements where you would have to provide both header 'name' and 'value', you can use convenient sub-elements to set those values directly.

Starting with version 4.1, the header enricher provides a `routing-slip` sub-element.
See xref:router/routing-slip.adoc[Routing Slip] for more information.

[[pojo-support]]
=== POJO Support

Often, a header value cannot be defined statically and has to be determined dynamically based on some content in the message.
That is why the header enricher lets you also specify a bean reference by using the `ref` and `method` attributes.
The specified method calculates the header value.
Consider the following configuration and a bean with a method that modifies a `String`:

[source,xml]
----
<int:header-enricher input-channel="in" output-channel="out">
    <int:header name="something" method="computeValue" ref="myBean"/>
</int:header-enricher>

<bean id="myBean" class="thing1.thing2.MyBean"/>
----

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

    public String computeValue(String payload){
        return payload.toUpperCase() + "_US";
    }
}
----

You can also configure your POJO as an inner bean, as the following example shows:

[source,xml]
----
<int:header-enricher  input-channel="inputChannel" output-channel="outputChannel">
    <int:header name="some_header">
        <bean class="org.MyEnricher"/>
    </int:header>
</int:header-enricher>
----

You can similarly point to a Groovy script, as the following example shows:

[source,xml]
----
<int:header-enricher  input-channel="inputChannel" output-channel="outputChannel">
    <int:header name="some_header">
        <int-groovy:script location="org/SampleGroovyHeaderEnricher.groovy"/>
    </int:header>
</int:header-enricher>
----

[[spel-support]]
=== SpEL Support

In Spring Integration 2.0, we introduced the convenience of the https://docs.spring.io/spring-framework/reference/core/expressions.html[Spring Expression Language (SpEL)] to help configure many different components.
The header enricher is one of them.
Look again at the POJO example shown earlier.
You can see that the computation logic to determine the header value is pretty simple.
A natural question would be: "Is there an even simpler way to accomplish this?".
That is where SpEL shows its true power.
Consider the following example:

[source,xml]
----
<int:header-enricher input-channel="in" output-channel="out">
    <int:header name="foo" expression="payload.toUpperCase() + '_US'"/>
</int:header-enricher>
----

By using SpEL for such simple cases, you no longer have to provide a separate class and configure it in the application context.
All you need do is configured the `expression` attribute with a valid SpEL expression.
The 'payload' and 'headers' variables are bound to the SpEL evaluation context, giving you full access to the incoming message.

[[configuring-a-header-enricher-with-java-configuration]]
=== Configuring a Header Enricher with Java Configuration

The following two examples show how to use Java Configuration for header enrichers:

[source, java]
----
@Bean
@Transformer(inputChannel = "enrichHeadersChannel", outputChannel = "emailChannel")
public HeaderEnricher enrichHeaders() {
    Map<String, ? extends HeaderValueMessageProcessor<?>> headersToAdd =
            Collections.singletonMap("emailUrl",
                      new StaticHeaderValueMessageProcessor<>(this.imapUrl));
    HeaderEnricher enricher = new HeaderEnricher(headersToAdd);
    return enricher;
}

@Bean
@Transformer(inputChannel="enrichHeadersChannel", outputChannel="emailChannel")
public HeaderEnricher enrichHeaders() {
    Map<String, HeaderValueMessageProcessor<?>> headersToAdd = new HashMap<>();
    headersToAdd.put("emailUrl", new StaticHeaderValueMessageProcessor<String>(this.imapUrl));
    Expression expression = new SpelExpressionParser().parseExpression("payload.from[0].toString()");
    headersToAdd.put("from",
               new ExpressionEvaluatingHeaderValueMessageProcessor<>(expression, String.class));
    HeaderEnricher enricher = new HeaderEnricher(headersToAdd);
    return enricher;
}
----

The first example adds a single literal header.
The second example adds two headers, a literal header and one based on a SpEL expression.

[[configuring-a-header-enricher-with-the-java-dsl]]
=== Configuring a Header Enricher with the Java DSL

The following example shows Java DSL Configuration for a header enricher:

[source, java]
----
@Bean
public IntegrationFlow enrichHeadersInFlow() {
    return f -> f
                ...
                .enrichHeaders(h -> h.header("emailUrl", this.emailUrl)
                                     .headerExpression("from", "payload.from[0].toString()"))
                .handle(...);
}
----

[[header-channel-registry]]
=== Header Channel Registry

Starting with Spring Integration 3.0, a new sub-element `<int:header-channels-to-string/>` is available.
It has no attributes.
This new sub-element converts existing `replyChannel` and `errorChannel` headers (when they are a `MessageChannel`) to a `String` and stores the channels in a registry for later resolution, when it is time to send a reply or handle an error.
This is useful for cases where the headers might be lost -- for example, when serializing a message into a message store or when transporting the message over JMS.
If the header does not already exist, or it is not a `MessageChannel`, no changes are made.

Using this functionality requires the presence of a `HeaderChannelRegistry` bean.
By default, the framework creates a `DefaultHeaderChannelRegistry` with the default expiry (60 seconds).
Channels are removed from the registry after this time.
To change this behavior, define a bean with an `id` of `integrationHeaderChannelRegistry` and configure the required default delay by using a constructor argument (in milliseconds).

Since version 4.1, you can set a property called `removeOnGet` to `true` on the `<bean/>` definition, and the mapping entry is removed immediately on first use.
This might be useful in a high-volume environment and when the channel is only used once, rather than waiting for the reaper to remove it.

The `HeaderChannelRegistry` has a `size()` method to determine the current size of the registry.
The `runReaper()` method cancels the current scheduled task and runs the reaper immediately.
The task is then scheduled to run again based on the current delay.
These methods can be invoked directly by getting a reference to the registry, or you can send a message with, for example, the following content to a control bus:

[source]
----
"@integrationHeaderChannelRegistry.runReaper()"
----

This sub-element is a convenience, and is the equivalent of specifying the following configuration:

[source,xml]
----
<int:reply-channel
    expression="@integrationHeaderChannelRegistry.channelToChannelName(headers.replyChannel)"
    overwrite="true" />
<int:error-channel
    expression="@integrationHeaderChannelRegistry.channelToChannelName(headers.errorChannel)"
    overwrite="true" />
----

Starting with version 4.1, you can now override the registry's configured reaper delay so that the channel mapping is retained for at least the specified time, regardless of the reaper delay.
The following example shows how to do so:

[source,xml]
----
<int:header-enricher input-channel="inputTtl" output-channel="next">
    <int:header-channels-to-string time-to-live-expression="120000" />
</int:header-enricher>

<int:header-enricher input-channel="inputCustomTtl" output-channel="next">
    <int:header-channels-to-string
        time-to-live-expression="headers['channelTTL'] ?: 120000" />
</int:header-enricher>
----

In the first case, the time to live for every header channel mapping will be two minutes.
In the second case, the time to live is specified in the message header and uses an Elvis operator to use two minutes if there is no header.

[[payload-enricher]]
== Payload Enricher

In certain situations, the header enricher, as discussed earlier, may not be sufficient and payloads themselves may have to be enriched with additional information.
For example, order messages that enter the Spring Integration messaging system have to look up the order's customer based on the provided customer number and then enrich the original payload with that information.

Spring Integration 2.1 introduced the payload enricher.
The payload enricher defines an endpoint that passes a `Message` to the exposed request channel and then expects a reply message.
The reply message then becomes the root object for evaluation of expressions to enrich the target payload.

The payload enricher provides full XML namespace support through the `enricher` element.
In order to send request messages, the payload enricher has a `request-channel` attribute that lets you dispatch messages to a request channel.

Basically, by defining the request channel, the payload enricher acts as a gateway, waiting for the message sent to the request channel to return.
The enricher then augments the message's payload with the data provided by the reply message.

When sending messages to the request channel, you also have the option to send only a subset of the original payload by using the `request-payload-expression` attribute.

The enriching of payloads is configured through SpEL expressions, providing a maximum degree of flexibility.
Therefore, you can not only enrich payloads with direct values from the reply channel's `Message`, but you can use SpEL expressions to extract a subset from that message or to apply additional inline transformations, letting you further manipulate the data.

If you need only to enrich payloads with static values, you need not provide the `request-channel` attribute.

NOTE: Enrichers are a variant of transformers.
In many cases, you could use a payload enricher or a generic transformer implementation to add additional data to your message payloads.
You should familiarize yourself with all transformation-capable components that are provided by Spring Integration and carefully select the implementation that semantically fits your business case best.

[[payload-enricher-configuration]]
=== Configuration

The following example shows all available configuration options for the payload enricher:

[source,xml]
----
<int:enricher request-channel=""                           <1>
              auto-startup="true"                          <2>
              id=""                                        <3>
              order=""                                     <4>
              output-channel=""                            <5>
              request-payload-expression=""                <6>
              reply-channel=""                             <7>
              error-channel=""                             <8>
              send-timeout=""                              <9>
              should-clone-payload="false">                <10>
    <int:poller></int:poller>                              <11>
    <int:property name="" expression="" null-result-expression="'Could not determine the name'"/>   <12>
    <int:property name="" value="23" type="java.lang.Integer" null-result-expression="'0'"/>
    <int:header name="" expression="" null-result-expression=""/>   <13>
    <int:header name="" value="" overwrite="" type="" null-result-expression=""/>
</int:enricher>
----

<1> Channel to which a message is sent to get the data to use for enrichment.
Optional.
<2> Lifecycle attribute signaling whether this component should be started during the application context startup.
Defaults to true.
Optional.
<3> ID of the underlying bean definition, which is either an `EventDrivenConsumer` or a `PollingConsumer`.
Optional.
<4> Specifies the order for invocation when this endpoint is connected as a subscriber to a channel.
This is particularly relevant when that channel is using a "`failover`" dispatching strategy.
It has no effect when this endpoint is itself a polling consumer for a channel with a queue.
Optional.
<5> Identifies the message channel where a message is sent after it is being processed by this endpoint.
Optional.
<6> By default, the original message's payload is used as payload that is sent to the `request-channel`.
By specifying a SpEL expression as the value for the `request-payload-expression` attribute, you can use a subset of the original payload, a header value, or any other resolvable SpEL expression as the basis for the payload that is sent to the request-channel.
For the expression evaluation, the full message is available as the 'root object'.
For instance, the following SpEL expressions (among others) are possible: `payload.something`, `headers.something`, `new java.util.Date()`, `'thing1' + 'thing2'`
<7> Channel where a reply message is expected.
This is optional.
Typically, the auto-generated temporary reply channel suffices.
Optional.
<8> The channel to which an `ErrorMessage` is sent if an `Exception` occurs downstream of the `request-channel`.
This enables you to return an alternative object to use for enrichment.
If it is not set, an `Exception` is thrown to the caller.
Optional.


<9> Maximum amount of time in milliseconds to wait when sending a message to the channel, if the channel might block.
For example, a queue channel can block until space is available, if its maximum capacity has been reached.
Internally, the `send()` timeout is set on the `MessagingTemplate` and ultimately applied when invoking the send operation on the `MessageChannel`.
By default, the `send()` timeout is set to '30'.
Optional.
<10> Boolean value indicating whether any payload that implements `Cloneable` should be cloned prior to sending the message to the request channel for acquiring the enriching data.
The cloned version would be used as the target payload for the ultimate reply.
The default is `false`.
Optional.
<11> Lets you configure a message poller if this endpoint is a polling consumer.
Optional.
<12> Each `property` sub-element provides the name of a property (through the mandatory `name` attribute).
That property should be settable on the target payload instance.
Exactly one of the `value` or `expression` attributes must be provided as well -- the former for a literal value to set and the latter for a SpEL expression to be evaluated.
The root object of the evaluation context is the message that was returned from the flow initiated by this enricher -- the input message if there is no request channel or the application context (using the `@<beanName>.<beanProperty>` SpEL syntax).
Starting with version 4.0, when specifying a `value` attribute, you can also specify an optional `type` attribute.
When the destination is a typed setter method, the framework coerces the value appropriately (as long as a `PropertyEditor`) exists to handle the conversion.
If, however, the target payload is a `Map`, the entry is populated with the value without conversion.
The `type` attribute lets you, for example, convert a `String` containing a number to an `Integer` value in the target payload.
Starting with version 4.1, you can also specify an optional `null-result-expression` attribute.
When the `enricher` returns null, it is evaluated, and the output of the evaluation is returned instead.
<13> Each `header` sub-element provides the name of a message header (through the mandatory `name` attribute).
Exactly one of the `value` or `expression` attributes must also be provided -- the former for a literal value to set and the latter for a SpEL expression to be evaluated.
The root object of the evaluation context is the message that was returned from the flow initiated by this enricher -- the input message if there is no request channel or the application context (using the '@<beanName>.<beanProperty>' SpEL syntax).
Note that, similarly to the `<header-enricher>`, the `<enricher>` element's `header` element has `type` and `overwrite` attributes.
However, a key difference is that, with the `<enricher>`, the `overwrite` attribute is `true` by default, to be consistent with the `<enricher>` element's `<property>` sub-element.
Starting with version 4.1, you can also specify an optional `null-result-expression` attribute.
When the `enricher` returns null, it is evaluated, and the output of the evaluation is returned instead.

[[payload-enricher-examples]]
=== Examples

This section contains several examples of using a payload enricher in various situations.

TIP: The code samples shown here are part of the Spring Integration Samples project.
See xref:samples.adoc#samples-impl[Spring Integration Samples].

In the following example, a `User` object is passed as the payload of the `Message`:

[source,xml]
----
<int:enricher id="findUserEnricher"
              input-channel="findUserEnricherChannel"
              request-channel="findUserServiceChannel">
    <int:property name="email"    expression="payload.email"/>
    <int:property name="password" expression="payload.password"/>
</int:enricher>
----

The `User` has several properties, but only the `username` is set initially.
The enricher's `request-channel` attribute is configured to pass the `User` to the `findUserServiceChannel`.

Through the implicitly set `reply-channel`, a `User` object is returned and, by using the `property` sub-element, properties from the reply are extracted and used to enrich the original payload.

[[how-do-i-pass-only-a-subset-of-data-to-the-request-channel]]
=== How Do I Pass Only a Subset of Data to the Request Channel?

When using a `request-payload-expression` attribute, a single property of the payload instead of the full message can be passed on to the request channel.
In the following example, the username property is passed on to the request channel:

[source,xml]
----
<int:enricher id="findUserByUsernameEnricher"
              input-channel="findUserByUsernameEnricherChannel"
              request-channel="findUserByUsernameServiceChannel"
              request-payload-expression="payload.username">
    <int:property name="email"    expression="payload.email"/>
    <int:property name="password" expression="payload.password"/>
</int:enricher>
----

Keep in mind that, although only the username is passed, the resulting message to the request channel contains the full set of `MessageHeaders`.

[[how-can-i-enrich-payloads-that-consist-of-collection-data]]
==== How Can I Enrich Payloads that Consist of Collection Data?

In the following example, instead of a `User` object, a `Map` is passed in:

[source,xml]
----
<int:enricher id="findUserWithMapEnricher"
              input-channel="findUserWithMapEnricherChannel"
              request-channel="findUserByUsernameServiceChannel"
              request-payload-expression="payload.username">
    <int:property name="user" expression="payload"/>
</int:enricher>
----

The `Map` contains the username under the `username` map key.
Only the `username` is passed on to the request channel.
The reply contains a full `User` object, which is ultimately added to the `Map` under the `user` key.

[[how-can-i-enrich-payloads-with-static-information-without-using-a-request-channel]]
=== How Can I Enrich Payloads with Static Information without Using a Request Channel?

The following example does not use a request channel at all but solely enriches the message's payload with static values:

[source,xml]
----
<int:enricher id="userEnricher"
              input-channel="input">
    <int:property name="user.updateDate" expression="new java.util.Date()"/>
    <int:property name="user.firstName" value="William"/>
    <int:property name="user.lastName"  value="Shakespeare"/>
    <int:property name="user.age"       value="42"/>
</int:enricher>
----

Note that the word, 'static', is used loosely here.
You can still use SpEL expressions for setting those values.
