Conditional Annotation in Spring 4.0

In this article I shall throw some light on one of the new features of Spring 4Conditional Annotation Type. In the earlier versions of Spring you could handle conditions as below:

  • In Spring with versions earlier to 3.1, you had to use Spring Expression Language (SPeL).
  • With Spring 3.1, a new feature called profiles was introduced which helped us to handle conditions.

Let us see each of these approaches and then understand the Conditional Annotation type in Spring 4.

Spring Expression Language (SPeL)

The SPeL has a Ternary Operator (If-Then-Else) which can be used as conditional statement in your configuration file (spring.xml) as in the example below:

<bean id="flag">
   <constructor-arg value="#{systemProperties['system.propery.flag'] ?: false }" />
</bean>
<bean id="bean">
    <property name="property" value="#{ flag ? 'yes' : 'no' }"/>
</bean>

I have Spring bean (MyBean) whose value depends on the value of a property (property). MyBean is set dynamically based on environment it runs.

Using Profiles

The second approach as mentioned would be to use of profiles which got introduced since Spring 3.1.

<!-- default configuration - will be loaded if no profile is specified -->
<!-- This will only work if it's put at the end of the configuration file -->
<!-- so no bean definitions after that -->
<beans profile="default">
     <import resource="classpath:default.xml" />
</beans>
<!-- some other profile -->
<beans profile="otherProfile">
    <import resource="classpath:other-profile.xml" />
</beans>

Conditional Annotation Type In Spring 4

Now let us understand the Conditional Annotation type. This annotation will be introduced in Spring 4, which is set to release by the end of 2013. However, anyone can download the early access release and try the new features. As the official document defines the conditionals class as “Indicates that a component is is only eligible for registration when all specified conditions match”. The primary objective is to create the bean only after the set of conditions are met.

The declaration of Conditional interface is as below:

 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.TYPE, ElementType.METHOD)
 public @interface Conditional{
Class <!--?extends Condition-->[] value();
 }

The @Conditional annotation may be used in any of the following ways:

  1. as a type-level annotation on any class directly or indirectly annotated with @Component, including @Configuration classes.
  2. as a meta-annotation, for the purpose of composing custom stereotype annotations.
  3. as a method-level annotation on any @Bean method

If a @Configuration class is marked with @Conditional, all of the @Bean methods and @Import annotations associated with that class will be subject to the conditions.

The condition interface is as follows:


public interface Condition{
/** Determine if the condition matches.
* @param context the condition context
* @param metadata meta-data of the {@link AnnotationMetadata class} or
* {@link Method method} being checked.
* @return {@code true} if the condition matches and the component can be registered
* or {@code false} to veto registration.
*/
boolean matches(ConditionContext context, AnnotatedTypeMedata metadata);
}

Let’s see an example:


public class SystemPropertyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return (System.getProperty("flag") != null);
}
}

class SystemPropertyAbsentCondition implements Condition {

@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return (System.getProperty("flag") == null);

}
}

Here we have two classes SystemPropertyCondition and SystemPropertyAbsentCondition. Both these classes implement Condition interface. The overridden method returns a boolean value based on the property flag.

Now lets define bean definitions one with positive condition and one that specifies the negative condition as below:


@Bean
@Conditional(SystemPropertyCondition.class)
public SampleService service1() {
return new SampleServiceImpl1();
}

@Bean
@Conditional(SystemPropertyAbsentCondition.class)
public SampleService service2() {
return new SampleServiceImpl2();
}

The Conditional annotation can also be used for modifying the behavior of Spring 3.1 based Profiles itself that I mentioned in above sections. Profiles is internally now based on meta-annotation based Conditional. @Profile annotation has been re factored.

Summary

In this article I have tried to consolidate the Conditional annotation type in Spring 4. Also note that condition annotations are not inherited. If a super class has the Conditional annotation, the sub classes will not have that conditions. If you try few examples listed above, it is easy for you to understand this concept. Hope you liked it.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Pin It on Pinterest

Share This

Share this post with your friends!

Share This

Share this post with your friends!