Advanced config with configuration meta-data in Spring Boot

After a short introduction to configuration meta-data and covering the basics in my previous post called Pimp your config with configuration meta-data in Spring Boot, it is time to take a look at how to take this one step further and further customize the configuration. In this post, I plan to present deprecation of a configuration property and discuss various value providers allowing for one of the most comfortable application configuration I have ever experienced (long gone are the times of making typos in your configuration while trying to write out the fully qualified class name or resource path – let’s rejoice. 🙂

Deprecation of a property

When it comes to configuration, one sure way of inviting trouble is the introduction of sudden and undocumented breaking change that can cause failure during the application initialization or runtime. Spring Boot introduced an option to mark and document a property to be deprecated in order to counter this scenario. Keeping with the spirit of simple declaration, once you have a new (replacement) property ready to go, all you need to do is add deprecation JSON node into property description in additional-spring-configuration-metadata.json file:

Deprecation of a property

JavaScript

1

2

3

4

5

6

7

8

9

10

...

{

"name":"my.property",

"defaultValue":"something",

"deprecation":{

"replacement":"my.new-property",

"reason":"This property is no longer needed."

}

}

...

After recompilation of the project, tools supporting this feature will pick up the change and reflect it based on their settings. Following picture depicts a list of available configuration properties with the deprecated one clearly marked.

In case you have already used a deprecated property somewhere in your properties file, things might get a bit weird based on the color theme and IDE you are using. I like to use IDEA with Obsidian theme which results in the following text highlighting. It could have been done better but once you get used to it and understand what each color means there are no problems. Just a little something to keep in mind.

You can also dig deeper and see why this property was marked deprecated. Just invoke the documentation for this property (by pressing CTRL + Q by default in IDEA) and you will be presented something similar to this window rendering the metadata that I defined earlier in the additional-spring-configuration-metadata.json file. This lookup works for all of the properties and it depends on your code and additional configuration metadata how detailed and descriptive it gets.

Having a link to the property that is supposed to replace / substitute the property at hand is particularly useful. This means that you can use intention actions (invoked by pressing ALT + ENTER by default in IDEA) and execute a single hit replacement of the deprecated property. You are all done in case the property value can remain unchanged. Otherwise you need to update the value as well. Pretty neat!

Value providers

Value providers are available only to manually provided hints (using the file additional-spring-configuration-metadata.json). Spring Boot defines them as a way to describe the list of potential values for a property by associating a provider to attach a well-defined semantic to a property so that a tool can discover the list of potential values based on the project’s context. This might sound a bit vague however it is really cool feature allowing you to leverage almost any aspect of your project from class hierarchy, resource structure or Spring’s own context.

Class reference

Let’s start with something really simple yet very practical – class reference provider. In case I want to configure which strategy should be used in my application based on where the application is deployed, I might implement several strategy implementations and create a property to capture this piece of configuration. Each of my strategies implements a single IStrategy interface. By providing a simple provider declaration in the hints section of additional-spring-configuration-metadata.json file, I can achieve significant simplification of filling in of this property.

Example of class referencing

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

...

{

"name":"my.strategy",

"providers":[

{

"name":"class-reference",

"parameters":{

"target":"com.jakubstas.s3downloader.strategy.IStrategy"

}

}

]

}

...

Once you update your manually entered metadata and recompile the project, the strategy property appears in the list of available properties. Nothing new here.

However, when it comes to value selection the list of available values is restricted to implementations of defined interface. This can be useful when you need to configure which class / implementation to use or any other aspect of configuration like this.

The cool thing about this is that you don’t have to bother with providing additional descriptions for each and every available class since you still have the ability to use the documentation look-up action (by pressing CTRL + Q by default in IDEA). This allows developers to simply browse through the available options and select the one that suits the best very comfortably and without breaking any sweat.

Handle as

Handle as is another pretty cool provider available to you. It allows you to substitute the type of the property to a more high-level type. Which is just a fancy way of saying that you want your IDE to treat this string property as a Resource without creating an explicit dependency on any given framework class that might not be on the classpath further down the road. This provider is like a chameleon compared to the previously discussed one – it allows for auto-completion of stuff like charsets, mime-types, enums, locales or resources and supports also the use of collections.

This being said, we might want to use different terms and conditions information in our application and also be able to switch between different versions of each without the need to release the whole thing. New property was introduced to my configuration to support this requirement. By providing a simple provider declaration in the hints section of additional-spring-configuration-metadata.json like the one in this snippet, I will be able to browse my resources only and quickly navigate to the file I want to use.

Handle the property as a Resource

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

...

{

"name":"my.terms-and-conditions",

"providers":[

{

"name":"handle-as",

"parameters":{

"target":"org.springframework.core.io.Resource"

}

}

]

}

...

First thing that you are presented with is the choice of resource type you want to use (yes, it supports resource string prefixes 🙂 ).

I want to go with classpath resource and I navigate my way to my file. Since you might want to use a folder itself as a resource, you need to provide file separators yourself.

Others

There are several other value providers worth checking out that I won’t discuss in the same level of detail as the previous two. Let’s take a quick look at what else we can use:

any

Permit any additional value to be provided.

logger name

Auto-complete valid logger names. Typically, package and class names available in the current project can be auto-completed.

Conclusion

And that is all I have to say about configuration meta-data support in Spring Boot. I hope these two posts inspired you to do your own research of this feature and to play around with it. I can honestly say that it is really not hard to set it up and it makes your life easier. And even though it is not almighty solution fixing all the issues with application configuration, I am willing to make use of an incremental improvement like this any day. What is your experience with this approach to configuration? Let me know in the comment section.

If you enjoyed this post, then make sure you subscribe to my Newsletter and/or Feed

FYI, you can also annotate the getter of the deprecated property with @DeprecatedConfigurationProperty and we will generate that meta-date entry automatically for you. When you deprecate a property, it is backed by a public getter/setter anyway so that should be included in the deprecation as well.

“Value providers are available only to manually provided hints”. I find this a bit confusing. You can add value provider to any key (including those generated automatically). All you need to do is to add a hint entry that references the key you want to customize.

Hi Stéphane, thanks for your insights on both articles. I must have missed @DeprecatedConfigurationProperty annotation in the latest Spring Boot documentation (http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/). If it is not there it might be worth including. As for the hints remark, this might be caused by my English 🙂 All I meant to say is that one needs to specify it manually in additional-spring-configuration-metadata.json file. Or is there any other way of doing it? Anyways, I will modify the article according to your comment tomorrow.