Filter

Message filters are used to decide whether a Message should be passed along or dropped based on some criteria, such as a message header value or message content itself. Therefore, a message filter is similar to a router, except that, for each message received from the filter’s input channel, that same message may or may not be sent to the filter’s output channel. Unlike the router, it makes no decision regarding which message channel to send the message to but decides only whether to send the message at all.

As we describe later in this section, the filter also supports a discard channel. In certain cases, it can play the role of a very simple router (or “switch”), based on a boolean condition.

In Spring Integration, you can configure a message filter as a message endpoint that delegates to an implementation of the MessageSelector interface. That interface is itself quite simple, as the following listing shows:

public interface MessageSelector {

    boolean accept(Message<?> message);

}

The MessageFilter constructor accepts a selector instance, as the following example shows:

MessageFilter filter = new MessageFilter(someSelector);

In combination with the namespace and SpEL, you can configure powerful filters with very little Java code.

Configuring a Filter with XML

You can use the <filter> element is used to create a message-selecting endpoint. In addition to input-channel and output-channel attributes, it requires a ref attribute. The ref can point to a MessageSelector implementation, as the following example shows:

<int:filter input-channel="input" ref="selector" output-channel="output"/>

<bean id="selector" class="example.MessageSelectorImpl"/>

Alternatively, you can add the method attribute. In that case, the ref attribute may refer to any object. The referenced method may expect either the Message type or the payload type of inbound messages. The method must return a boolean value. If the method returns 'true', the message is sent to the output channel. The following example shows how to configure a filter that uses the method attribute:

<int:filter input-channel="input" output-channel="output"
    ref="exampleObject" method="someBooleanReturningMethod"/>

<bean id="exampleObject" class="example.SomeObject"/>

If the selector or adapted POJO method returns false, a few settings control the handling of the rejected message. By default, (if configured as in the preceding example) rejected messages are silently dropped. If rejection should instead result in an error condition, set the throw-exception-on-rejection attribute to true, as the following example shows:

<int:filter input-channel="input" ref="selector"
    output-channel="output" throw-exception-on-rejection="true"/>

If you want rejected messages to be routed to a specific channel, provide that reference as the discard-channel, as the following example shows:

<int:filter input-channel="input" ref="selector"
    output-channel="output" discard-channel="rejectedMessages"/>

If the throwExceptionOnRejection == false and no discardChannel is provided, the message is silently dropped and an o.s.i.filter.MessageFilter instance just emits a warning log message (starting with version 6.1) about this discarded message. To drop the message with no warning in the logs, a NullChannel can be configured as the discardChannel on the filter. The goal of the framework is to not be completely silent, by default, requiring an explicit option to be set, if that is the desired behavior.

See also Advising Filters.

Message filters are commonly used in conjunction with a publish-subscribe channel. Many filter endpoints may be subscribed to the same channel, and they decide whether to pass the message to the next endpoint, which could be any of the supported types (such as a service activator). This provides a reactive alternative to the more proactive approach of using a message router with a single point-to-point input channel and multiple output channels.

We recommend using a ref attribute if the custom filter implementation is referenced in other <filter> definitions. However, if the custom filter implementation is scoped to a single <filter> element, you should provide an inner bean definition, as the following example shows:

<int:filter method="someMethod" input-channel="inChannel" output-channel="outChannel">
  <beans:bean class="org.foo.MyCustomFilter"/>
</filter>
Using both the ref attribute and an inner handler definition in the same <filter> configuration is not allowed, as it creates an ambiguous condition and throws an exception.
If the ref attribute references a bean that extends MessageFilter (such as filters provided by the framework itself), the configuration is optimized by injecting the output channel into the filter bean 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. However, this optimization applies only if you do not provide any filter-specific attributes in the filter XML definition. If you inadvertently reference the same message handler from multiple beans, you get a configuration exception.

With the introduction of SpEL support, Spring Integration added the expression attribute to the filter element. It can be used to avoid Java entirely for simple filters, as the following example shows:

<int:filter input-channel="input" expression="payload.equals('nonsense')"/>

The string passed as the value of the expression attribute is evaluated as a SpEL expression with the message available in the evaluation context. If you must include the result of an expression in the scope of the application context, you can use the #{} notation, as defined in the SpEL reference documentation, as the following example shows:

<int:filter input-channel="input"
            expression="payload.matches(#{filterPatterns.nonsensePattern})"/>

If the expression itself needs to be dynamic, you can use an 'expression' sub-element. That provides a level of indirection for resolving the expression by its key from an ExpressionSource. That is a strategy interface that you can implement directly, or you can rely upon a version available in Spring Integration that loads expressions from a “resource bundle” and can check for modifications after a given number of seconds. All of this is demonstrated in the following configuration example, where the expression could be reloaded within one minute if the underlying file had been modified:

<int:filter input-channel="input" output-channel="output">
    <int:expression key="filterPatterns.example" source="myExpressions"/>
</int:filter>

<beans:bean id="myExpressions"
    class="o.s.i.expression.ReloadableResourceBundleExpressionSource">
    <beans:property name="basename" value="config/integration/expressions"/>
    <beans:property name="cacheSeconds" value="60"/>
</beans:bean>

If the ExpressionSource bean is named expressionSource, you need not provide the` source` attribute on the <expression> element. However, in the preceding example, we show it for completeness.

The 'config/integration/expressions.properties' file (or any more-specific version with a locale extension to be resolved in the typical way that resource-bundles are loaded) can contain a key/value pair, as the following example shows:

filterPatterns.example=payload > 100
All of these examples that use expression as an attribute or sub-element can also be applied within transformer, router, splitter, service-activator, and header-enricher elements. The semantics and role of the given component type would affect the interpretation of the evaluation result, in the same way that the return value of a method-invocation would be interpreted. For example, an expression can return strings that are to be treated as message channel names by a router component. However, the underlying functionality of evaluating the expression against the message as the root object and resolving bean names if prefixed with '@' is consistent across all of the core EIP components within Spring Integration.

Configuring a Filter with Annotations

The following example shows how to configure a filter by using annotations:

public class PetFilter {
    ...
    @Filter  (1)
    public boolean dogsOnly(String input) {
        ...
    }
}
1 An annotation indicating that this method is to be used as a filter. It must be specified if this class is to be used as a filter.

All the configuration options provided by the XML element are also available for the @Filter annotation.

The filter can be either referenced explicitly from XML or, if the @MessageEndpoint annotation is defined on the class, detected automatically through classpath scanning.