8. Filter

8.1 Introduction

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 even content within the Message 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 to but only decides whether to send.

[Note]Note
As you will see momentarily, the Filter does also support a discard channel, so in certain cases it can play the role of a very simple router (or "switch") based on a boolean condition.

In Spring Integration, a Message Filter may be configured as a Message Endpoint that delegates to some implementation of the MessageSelector interface. That interface is itself quite simple:

 public interface MessageSelector {

     boolean accept(Message<?> message);

 }

The MessageFilter constructor accepts a selector instance:

 MessageFilter filter = new MessageFilter(someSelector);

In combination with the namespace and SpEL very powerful filters can be configured with very little java code.

8.2 The <filter> Element

The <filter> element is used to create a Message-selecting endpoint. In addition to "input-channel" and "output-channel" attributes, it requires a "ref". The "ref" may point to a MessageSelector implementation:

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

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

Alternatively, the "method" attribute can be added at which point the "ref" may refer to any object. The referenced method may expect either the Message type or the payload type of inbound Messages. The return value of the method must be a boolean value. Any time the method returns 'true', the Message will be passed along to the output-channel.

 <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, there are a few settings that control the fate of the rejected Message. By default (if configured like the example above), the rejected Messages will be silently dropped. If rejection should instead indicate an error condition, then set the 'throw-exception-on-rejection' flag to true:

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

If you want the rejected messages to go to a specific channel, provide that reference as the 'discard-channel':

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

[Note]Note
A common usage for Message Filters is in conjunction with a Publish Subscribe Channel. Many filter endpoints may be subscribed to the same channel, and they decide whether or not to pass the Message for the next endpoint which could be any of the supported types (e.g. 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.

Using a "ref" attribute is generally recommended if the custom filter implementation can be reused in other <filter> definitions. However if the custom filter implementation should be scoped to a single <filter> element, provide an inner bean definition:

<filter method="someMethod" input-channel="inChannel" output-channel="outChannel">
  <beans:bean class="org.foo.MyCustomFilter"/>
</filter>

[Note]Note

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 it will therefore result in an Exception being thrown.

With the introduction of SpEL Spring Integration has added the expression attribute to the filter element. It can be used to avoid Java entirely for simple filters.

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

The string passed as the expression attribute will be evaluated as a SpEL expression in the context of the message. If it is needed to 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 SpEL reference documentation .

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

If the Expression itself needs to be dynamic, then an 'expression' sub-element may be used. 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 sample where the Expression could be reloaded within one minute if the underlying file had been modified. If the ExpressionSource bean is named "expressionSource", then it is not necessary to provide the "source" attribute on the <expression> element, but in this case it's shown for completeness.

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

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

Then, 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) would contain a key/value pair:

          filterPatterns.example=payload > 100

[Note]Note
All of the examples that use "expression" as an attribute or sub-element can also be applied within transformer, router, splitter, service-activator, and header-enricher elements. Of course, the semantics/role of the given component type would affect the interpretation of the evaluation result in the same way that the return or 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.