Spring Annotation based Condition Example

0

We use Conditions to programatically decide whether to include or exclude component registration. We specify conditions using @Conditional annotation, the attribute values are Condition classes. A condition has access mainly to the bean factory and the annotation meta data. In this example, we will see how to write a Condition that is based on the annotation meta data.

If you want to know more about @Conditional annotation, read here.

Annotation based Conditions

Below condition checks on the annotation metadata and fails if annotated with @Test. Include this annotation if you think the bean is meant for just test purpose.

IfAnnotationTestCondition:

package com.javarticles.spring.annotations;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class IfAnnotationTestCondition implements Condition {

    public boolean matches(ConditionContext context,
            AnnotatedTypeMetadata metadata) {
        return !metadata.isAnnotated(Test.class.getName());
    }
}

Here is another annotation that queries the FeatureMode annotation’s value. If the feature is used in test purpose, we will use FeatureMode("test"). The below condition fails if the @FeatureMode is for test.

IfAnnotationValueTestCondition:

package com.javarticles.spring.annotations;

import java.util.Map;

import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.ConfigurationCondition;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class IfAnnotationValueTestCondition implements ConfigurationCondition {

    public boolean matches(ConditionContext context,
            AnnotatedTypeMetadata metadata) {
        if (!metadata.isAnnotated(FeatureMode.class.getName())) {
            return true;
        }
        Map<String, Object> attributes = metadata.getAnnotationAttributes(FeatureMode.class.getName());
        if (attributes== null) {
            return true;
        }
        String value = (String) attributes.get("value");
        return value != null && !value.equals("test");
    }

    public ConfigurationPhase getConfigurationPhase() {
        return ConfigurationPhase.REGISTER_BEAN;
    }
}

Define beans

Let’s now define some beans. A DevBean and couple of test beans.

DevBean:

package com.javarticles.spring.annotations;

import org.springframework.context.annotation.Configuration;

@Configuration("devBean")
@FeatureMode("prod")
public class DevBean {
}

For test beans, we will also add the Conditional annotations and pass in the conditions created above.

TestBean1:

package com.javarticles.spring.annotations;

import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration("testBean1")
@Test
@Conditional({IfAnnotationValueTestCondition.class, IfAnnotationTestCondition.class})
public class TestBean1 {
}

TestBean2:

package com.javarticles.spring.annotations;

import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration("testBean2")
@FeatureMode("test")
@Conditional({IfAnnotationValueTestCondition.class, IfAnnotationTestCondition.class})
public class TestBean2 {
}

Here are the custom annotations that we rely on.

Test:

package com.javarticles.spring.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Test {
}

FeatureMode:

package com.javarticles.spring.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FeatureMode {
    String value();
}

Run the example

The main example tries to import DevBean and the test beans TestBean1 and TestBean2.

SpringAnnotationBasedConditionExample:

package com.javarticles.spring.annotations;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import({DevBean.class, TestBean1.class, TestBean2.class})
public class SpringAnnotationBasedConditionExample {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        try {
            ctx.register(SpringAnnotationBasedConditionExample.class);
            ctx.refresh();
            System.out.println("Has testBean1? " + ctx.containsBean("testBean1"));
            System.out.println("Has testBean2? " + ctx.containsBean("testBean2"));
            System.out.println("Has devBean? " + ctx.containsBean("devBean"));
        } finally {
            ctx.close();
        }
    }
}

Because of the conditions only the dev bean gets registered whereas the test beans doesn’t as the conditions doesn’t match.

Output:

Jan 31, 2016 12:01:19 PM org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
INFO: Refreshing org.spring[email protected]4783da3f: startup date [Sun Jan 31 12:01:19 IST 2016]; root of context hierarchy
Has testBean1? false
Has testBean2? false
Has devBean? true
Jan 31, 2016 12:01:19 PM org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
INFO: Closing org.spring[email protected]4783da3f: startup date [Sun Jan 31 12:01:19 IST 2016]; root of context hierarchy

Download the source code

This was an example about Spring Condition based on annotation metadata.

You can download the source code here: springAnnotationBasedConditionExample.zip
Share.

Comments are closed.