Handle locations deprecation of Spring Boot @ConfigurationProperties
One of things changed in Spring Boot 1.4.0 is the deprecation of the locations property of the @ConfigurationProperties annotation. Some discussion around this topic happened here and here.
The explanation given by Spring's developers is understandable and I think they are right, but I also think that there are cases in which a project has a "long configuration" made of many different keys, which have been spread into several files, semantically named, and bound to pojos injected into applications beans.
So, I'll try to explain what I understood: @ConfigurationProperties represent the application configuration, which is made of data source connections, jackson configuration, http configuration and so on, so it refers to the environment in which the application will run. This is different from the application behavior, or behavior configuration, or application properties, which represent the configuration of the business logic of the application (not the application itself). In other words it was possible to use the @ConfigurationProperties annotation to load and keep in memory a lot of stuff that was not strictly related to the application itself, but to its behavior.
An Example
An example? Take this simple use case: you have users in your application, and each of them has an homepage which responds to /users/{id}. Now, for whatever reason, you need to redirect old user pages to new ones, for example /users/45699 would be redirected to /users/7534. This must be done for many many users, but not for all of them. So basically in your controller, you need to check if the {id} path variable is contained in the list of redirectable users, and in that case generate a RedirectView instead of a plain ModelAndView.
I imagine a map, where the key is the old user id, and the value is the new user id. You can store this map wherever you want (database, nosql, etc). I decided to take advantage of the @ConfigurationProperties annotation, and store this in a yml file. That file was then bound to a Java class annotated with @Component and @ConfigurationProperties, which was then injected in the controller and that gave me a very easy way to get the redirection map in my business logic. Moreover I did not have the need to ask for a database (or any other storage option).
So, how did the @ConfigurationProperties annotation look like? It was like this: @ConfigurationProperties(locations = "classpath:config/redirection/old2new.yml"). With the locations deprecation, in Spring 1.5 it will not be possible to do this again, and this is a problem for several application already running in production.
A proposed solution
I took a look at what Spring is currently doing and I decided to develop a class to let me keep the previous behavior (or at least the most part). Actually one class and one annotation.
@ApplicationProperties
This annotation is very similar to the @ConfigurationProperties one. It lets you annotate your class and say it is a @Component
ApplicationPropertiesBindingPostProcessor
The class instead gets all the classes annotated with @ApplicationProperties annotation, binds them to a Java pojo and then registers them as resolvable dependencies.
Register ApplicationPropertiesBindingPostProcessor as a Bean
Last thing to do is to let my application know that there is a new bean of type ApplicationPropertiesBindingPostProcessor in the context.
Usage
You can now replace the @ConfigurationProperties with @ApplicationProperties, and in most cases it should continue to work exactly as before. And, of the same importance, you are one step closer to upgrade to Spring Boot 1.5.
Resources
You can find the example project here along with tests and example files.