Spring – Conditional annotation

Spring 4 has introduced a new annotation @Conditional. It is used to develop an “If-Then-Else” type of conditional checking for bean registration. Let us see how we can use @Conditional annotation to check a property value is dev or prod from environment. For learning we will use Java based configurations in this example.

Create Project Domain class with id, name and duration properties with getters only as shown below.

public class Project {

    private int id;
    private String name;
    private double duration;

    public Project(int id, String name, double duration) {
        this.id = id;
        this.name = name;
        this.duration = duration;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public double getDuration() {
        return duration;
    }
}

Create Utility classes to represent in-memory Databases. For simplicity, we are not interacting with Databases. DevDatabaseUtil class represents DEV database and ProductionDatabaseUtil class represents PROD database with some data.

public interface DataSource {

    List<Project> getProjectsList();
}
public class DevDatabaseUtil implements DataSource {

    @Override
    public List<Project> getProjectsList() {

        List<Project> projects = new ArrayList<>();
        Project projectWeb = new Project(1, "Web page for Qwerty", 160);
        Project projectWeb2 = new Project(2, "Web page for Asdfgh", 40);
        Project projectWeb3 = new Project(3, "Fix web page for Dfrtghy", 45.50);

        projects.add(projectWeb);
        projects.add(projectWeb2);
        projects.add(projectWeb3);

        return projects;
    }
}
public class ProductionDatabaseUtil implements DataSource {

    @Override
    public List<Project> getProjectsList() {

        List<Project> projects = new ArrayList<>();
        Project projectWeb = new Project(100, "Web page for Client 1", 230);
        Project projectWeb2 = new Project(200, "Web page for Client 2", 35);


        projects.add(projectWeb);
        projects.add(projectWeb2);

        return projects;
    }
}

Create a ProjectDAO class to represent DAO Layer.

public class ProjectService {

    private ProjectDAO projectDAO;

    public ProjectService(ProjectDAO projectDAO) {
        this.projectDAO = projectDAO;
    }

    public List<Project> getProjects() {
        return projectDAO.getProjects();
    }
}

Now it’s time to implement Conditional checking by using@Conditional annotation. Both condition checking classes implements Spring’s Condition interface matches() method. Both Conditional classes checks for “database.name” from environment. If this values is “dev”, then DevDataSourceCondition’s matches() method returns true. Otherwise false. In the same way, if this property value is “prod”, then ProdDataSourceCondition’s matches() method returns true. Otherwise false.

public class DevDataSourceCondition implements Condition {

    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        String dbname = conditionContext.getEnvironment().getProperty("database.name");
        return dbname.equalsIgnoreCase("dev");
    }
}
public class ProductionDataSourceCondition implements Condition {

    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {

        String dbname = conditionContext.getEnvironment().getProperty("database.name");
        return dbname.equalsIgnoreCase("prod");
    }
}

Create Spring’s Java-based configuration classes

@Configuration
public class ProjectConfig {

    @Autowired
    private DataSource dataSource;

    @Bean
    public ProjectService projectService() {
        return new ProjectService(projectDAO());
    }

    @Bean
    public ProjectDAO projectDAO() {
        System.out.println("ProjectDAO projectDAO()" + dataSource);
        return new ProjectDAO(dataSource);
    }
}
@Configuration
public class ProjectDataSourceConfig {

    @Bean(name="dataSource")
    @Conditional(value=DevDataSourceCondition.class)
    public DataSource getDevDataSource() {
        return new DevDatabaseUtil();
    }

    @Bean(name="dataSource")
    @Conditional(ProductionDataSourceCondition.class)
    public DataSource getProdDataSource() {
        return new ProductionDatabaseUtil();
    }

}

Now it’s time to write JUnits to test Spring’s @Conditional classes.

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringForBlogDemoApplication.class)
public class ProdConditionalTest {

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void testProdDataSource() {
        ProjectService service = (ProjectService) applicationContext.getBean("projectService");
        assertNotNull(service);
        List<Project> projects = service.getProjects();
        assertEquals(2, projects.size());
        assertEquals("Web page for Client 1", projects.get(0).getName());
        assertEquals("Web page for Client 2", projects.get(1).getName());
    }
}
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringForBlogDemoApplication.class)
public class DevConditionalTest {

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void testDevDataSource() {
        ProjectService service = (ProjectService) applicationContext.getBean("projectService");
        assertNotNull(service);
        List<Project> projects = service.getProjects();
        assertEquals(3, projects.size());
        assertEquals("Web page for Qwerty", projects.get(0).getName());
        assertEquals("Web page for Asdfgh", projects.get(1).getName());
        assertEquals("Fix web page for Dfrtghy", projects.get(2).getName());
    }
}

 

Leave a Reply