Application Configuration - Spring Configuration Metadata
Customize the application using
In the article

The differences between the two approaches are described here - ConfigurationProperties vs. Value
In the picture above, the basic composition and principle of operation. The available system components, these are Spring components, simply classes, various constants, variables, etc., can be specified in the application.properties file, while at the time the development environment specifies options, checks are made. When the application starts, the specified values will be checked for compliance with the type, limitations, and if everything is satisfactory, the application will be launched. For example, it is very convenient to configure the application functionality from the list of available Spring components, below I will show how.
To create an application setup using ConfigurationProperties, you can start with a property class. It actually shows the properties, system components that we want to customize.
In the class prefix = “demo” will be used in application.properties, as a prefix to the property.
Here I announced two spring bins
In the AppProperties class, I specified a link to some available application service, I will change it in application.properties, I will have two implementations of it, and I will connect one of them in application.properties.

Here is their implementation
This is already enough to start setting up application.properties. But whenever changes are made to the class with ConfigurationProperties, you need to rebuild the project, after which a file will appear in the project

If you try to enter the wrong type, the IDE will tell.

Even if you leave it as it is and try to start the application, there will be a clear error

Additional metadata is only for the convenience of working with the application.properties in the IDE, if it is not necessary, you can not do it. For this, it is possible to specify in the additional help file (hints) and other information for the environment. To do this, copy the created file spring-configuration-metadata.json to
In it, it will be possible to list, for example, valid values for demo.vehicle
The “name” field contains the “demo.vehicle” certificate, and the “values” list of valid values. Now, if you rebuild the project and go to the file application.properties, then when you enter demo.vehicle, you will receive a list of valid values.

If you enter something other than the one proposed but of the same type, the editor will highlight, but the application will start in this case, since this is not strict restriction, but just a hint.

Earlier in the project, I declared two services MyDemoService1 and MyDemoService2 both implement the DemoService interface, now you can configure that only the services implementing this interface are available to the application.properties and, accordingly, selected in the AppProperties class. To do this, there are Providers. They can be specified in the additional-spring-configuration-metadata. Providers have several types of them can be viewed in the documentation, I will show an example for one, -
Sample Providers for DemoService:
After that, in the application.properties for the demo.service parameter a choice of two services will be available, you can see their description (description from the definition).

Now it is convenient to choose the desired service, change the functionality of the application. There is one point for object settings, Spring needs a little help to convert the string that is specified in the configuration into an object. To do this, a small class is derived from Converter.
The project class diagram shows how these services are separated from the main application and are accessible via AppProperties.

Output to console

Project structure

Full file additional-spring-configuration-metadata.json
Configuration Metadata Materials
@ConfigurationProperties
, as an alternative to use @Value
. In the article
- Configuring and changing application functionality through application.properties using ConfigurationProperties
- Integration of application.properties with IDE
- Check setting values

The differences between the two approaches are described here - ConfigurationProperties vs. Value
In the picture above, the basic composition and principle of operation. The available system components, these are Spring components, simply classes, various constants, variables, etc., can be specified in the application.properties file, while at the time the development environment specifies options, checks are made. When the application starts, the specified values will be checked for compliance with the type, limitations, and if everything is satisfactory, the application will be launched. For example, it is very convenient to configure the application functionality from the list of available Spring components, below I will show how.
Property Class
To create an application setup using ConfigurationProperties, you can start with a property class. It actually shows the properties, system components that we want to customize.
AppProperties.java
@ConfigurationProperties(prefix = "demo")
@ValidatedpublicclassAppProperties{
private String vehicle;
@Max(value = 999, message = "Value 'Property' should not be greater than 999")
private Integer value;
private Map<String,Integer> contexts;
private StrategyEnum strategyEnum;
private Resource resource;
private DemoService service;
public String getVehicle(){
return vehicle;
}
publicvoidsetVehicle(String vehicle){
this.vehicle = vehicle;
}
public Map<String, Integer> getContexts(){
return contexts;
}
publicvoidsetContexts(Map<String, Integer> contexts){
this.contexts = contexts;
}
public StrategyEnum getStrategyEnum(){
return strategyEnum;
}
publicvoidsetStrategyEnum(StrategyEnum strategyEnum){
this.strategyEnum = strategyEnum;
}
public Resource getResource(){
return resource;
}
publicvoidsetResource(Resource resource){
this.resource = resource;
}
public DemoService getService(){
return service;
}
publicvoidsetService(DemoService service){
this.service = service;
}
public Integer getValue(){
return value;
}
publicvoidsetValue(Integer value){
this.value = value;
}
@Overridepublic String toString(){
return"MyAppProperties{" +
"\nvehicle=" + vehicle +
"\n,contexts=" + contexts +
"\n,service=" + service +
"\n,value=" + value +
"\n,strategyEnum=" + strategyEnum +
'}';
}
}
In the class prefix = “demo” will be used in application.properties, as a prefix to the property.
Application class SpringApplication and project pom.xml
@SpringBootApplication@EnableConfigurationProperties({AppProperties.class})
@ImportResource(value= "classpath:context.xml")
publicclassDemoConfigProcessorApplication{
publicstaticvoidmain(String[] args){
ConfigurableApplicationContext context = SpringApplication.run(DemoConfigProcessorApplication.class, args);
AppProperties properties = context.getBean(AppProperties.class);
String perform = properties.getService().perform(properties.getVehicle());
System.out.println("perform: " + perform);
System.out.println(properties.toString());
}
}
<?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>demoConfigProcessor</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>demoConfigProcessor</name><description>Demo project for Spring Boot Configuration Processor</description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.0.RELEASE</version><relativePath/><!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>com.jayway.jsonpath</groupId><artifactId>json-path</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
Here I announced two spring bins
Spring context (context.xml)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="service1"class="com.example.demoConfigProcessor.MyDemoService1">
<description>Description MyDemoService 1</description>
</bean>
<bean id="service2"class="com.example.demoConfigProcessor.MyDemoService2">
<description>Description MyDemoService 2</description>
</bean>
</beans>
In the AppProperties class, I specified a link to some available application service, I will change it in application.properties, I will have two implementations of it, and I will connect one of them in application.properties.

Here is their implementation
Demoservice
publicinterfaceDemoService{
String perform(String value);
}
publicclassMyDemoService1implementsDemoService{
@Overridepublic String perform(String value){
return"Service №1: perform routine maintenance work on <" + value +">";
}
}
publicclassMyDemoService2implementsDemoService{
@Overridepublic String perform(String value){
return"Service №2: perform routine maintenance work on <" + value +">";
}
}
This is already enough to start setting up application.properties. But whenever changes are made to the class with ConfigurationProperties, you need to rebuild the project, after which a file will appear in the project
\target\classes\META-INF\spring-configuration-metadata.json
. Actually, the IDE uses it for editing in the application.properties file. I will indicate its structure in the link in the materials. This file will be created based on the AppProperties class. If you now open the application.properties file and start typing “demo”, the medium will start showing available properties. 
If you try to enter the wrong type, the IDE will tell.

Even if you leave it as it is and try to start the application, there will be a clear error

Adding additional metadata
Additional metadata is only for the convenience of working with the application.properties in the IDE, if it is not necessary, you can not do it. For this, it is possible to specify in the additional help file (hints) and other information for the environment. To do this, copy the created file spring-configuration-metadata.json to
\src\main\resources\META-INF\
and rename it to additional-spring-configuration-metadata.json
. In this file, I will be interested only in the “hints” section: [] In it, it will be possible to list, for example, valid values for demo.vehicle
"hints": [
{
"name": "demo.vehicle",
"values": [
{
"value": "car make A",
"description": "Car brand A is allowed."
},
{
"value": "car make B",
"description": "Car brand B is allowed."
}
]
}]
The “name” field contains the “demo.vehicle” certificate, and the “values” list of valid values. Now, if you rebuild the project and go to the file application.properties, then when you enter demo.vehicle, you will receive a list of valid values.

If you enter something other than the one proposed but of the same type, the editor will highlight, but the application will start in this case, since this is not strict restriction, but just a hint.

Earlier in the project, I declared two services MyDemoService1 and MyDemoService2 both implement the DemoService interface, now you can configure that only the services implementing this interface are available to the application.properties and, accordingly, selected in the AppProperties class. To do this, there are Providers. They can be specified in the additional-spring-configuration-metadata. Providers have several types of them can be viewed in the documentation, I will show an example for one, -
spring-bean-reference
. This type shows the names of the available beans in the current project. The list is limited to the base class or interface. Sample Providers for DemoService:
"hints": [
{
"name": "demo.service",
"providers": [
{
"name": "spring-bean-reference",
"parameters": {
"target": "com.example.demoConfigProcessor.DemoService"
}
}
]
}
]
After that, in the application.properties for the demo.service parameter a choice of two services will be available, you can see their description (description from the definition).

Now it is convenient to choose the desired service, change the functionality of the application. There is one point for object settings, Spring needs a little help to convert the string that is specified in the configuration into an object. To do this, a small class is derived from Converter.
Serviceconverter
@Component@ConfigurationPropertiesBindingpublicclassServiceConverterimplementsConverter<String, DemoService> {
@Autowiredprivate ApplicationContext applicationContext;
@Overridepublic DemoService convert(String source){
return (DemoService) applicationContext.getBean(source);
}
}
The project class diagram shows how these services are separated from the main application and are accessible via AppProperties.

Validation propertyYou can add checks available in the JSR 303 framework to the fields of the AppProperties class . I wrote about this here . The checked, convenient file of a configuration of the application will turn out.
Output to console

Project structure

Full file additional-spring-configuration-metadata.json
additional-spring-configuration-metadata
{
"groups": [
{
"name": "demo",
"type": "com.example.demoConfigProcessor.AppProperties",
"sourceType": "com.example.demoConfigProcessor.AppProperties"
}
],
"properties": [
{
"name": "demo.contexts",
"type": "java.util.Map<java.lang.String,java.lang.Integer>",
"sourceType": "com.example.demoConfigProcessor.AppProperties"
},
{
"name": "demo.vehicle",
"type": "java.lang.String",
"sourceType": "com.example.demoConfigProcessor.AppProperties"
}
],
"hints": [
{
"name": "demo.vehicle",
"values": [
{
"value": "car make A",
"description": "Car brand A is allowed."
},
{
"value": "car make B",
"description": "Car brand B is allowed."
}
]
},
{
"name": "demo.service",
"providers": [
{
"name": "spring-bean-reference",
"parameters": {
"target": "com.example.demoConfigProcessor.DemoService"
}
}
]
}
]
}
Configuration Metadata Materials