Monday, November 11, 2013

HOW-TO: Using @PropertySource annotation in Spring 4 with Java 7

Today I migrated one of my projects, that I am currently working on, to Spring 4.0. Since it is a really simple web application I use to learn and demo Spring features, I only needed to update the POM file of my project and change the Spring version. I deployed the project to Tomcat 7 server and apparently the application did not start. I saw this message in IntelliJ console: Failed to load bean class: pl.codeleak.t.config.RootConfig; nested exception is org.springframework.core.NestedIOException: Unable to collect imports; nested exception is java.lang.ClassNotFoundException: java.lang.annotation.Repeatable. What the ...?

java.lang.annotation.Repeatable annotation that is the meta annotation used to mark your annotations for multiple usage in Java 8 (but I am using Java 7 in the project). E.g.:


@Repeatable(Schedules.class)
public @interface Schedule { ... }

@Schedule(dayOfMonth="last")
@Schedule(dayOfWeek="Fri", hour="23")
public void doPeriodicCleanup() { ... }

This is well described here: http://docs.oracle.com/javase/tutorial/java/annotations/repeating.html.

Spring 4 utilizes this feature in its @PropertySource annotation. To remind you, @PropertySource annotation provides a mechanism for adding a source of name/value property pairs to Spring's Environment and it is used in conjunction with @Configuration classes. As you probably already know, I am using this feature in my own configuration:


@Configuration
@PropertySource("classpath:/datasource.properties")
public class DefaultDataSourceConfig implements DataSourceConfig {

    @Autowired
    private Environment env;

    @Override
    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getRequiredProperty("dataSource.driverClassName"));
        dataSource.setUrl(env.getRequiredProperty("dataSource.url"));
        dataSource.setUsername(env.getRequiredProperty("dataSource.username"));
        dataSource.setPassword(env.getRequiredProperty("dataSource.password"));
        return dataSource;
    }
}

The first think I thought, that Spring is not compatible with Java below 8 anymore. Impossible. While doing GitHub lookup I found a brand new @PropertySources annotation that is a container of @PropertySource annotations. And that was my solution for Java compatibility issue: using @PropertySources annotation on my configuration class like this:


@Configuration
@PropertySources(value = {@PropertySource("classpath:/datasource.properties")})
public class DefaultDataSourceConfig implements DataSourceConfig {

    @Autowired
    private Environment env;

}

And that's it! After this change my application started and I could see it is working just fine!

EDIT: See: https://jira.springsource.org/browse/SPR-11086

2 comments:

  1. Thanks for this. Looks like this was fixed in RC2 that was just released.

    https://jira.springsource.org/browse/SPR/fixforversion/14229

    ReplyDelete

Fork me on GitHub