Saturday, 4 May 2019

Explain @Conditional Annotation in Spring 4.0



In this article I shall throw some light on one of the new features of Spring 4, Conditional 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.




<beans profile="default">
     <import resource="classpath:default.xml" />
</beans>

<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 [] value();
 }

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

as a type-level annotation on any class directly or indirectly annotated with @Component, including @Configuration classes.
as a meta-annotation, for the purpose of composing custom stereotype annotations.
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.

Spring Boot @ConfigurationProperties and Properties File

 In this tutorial, you will learn to use @ConfigurationProperties to map properties files to POJO classes in Spring Boot application. Let’s ...