Appendix B. Configuration meta-data

Spring Boot jars are shipped with meta-data files that provide details of all supported configuration properties. The files are designed to allow IDE developers to offer contextual help and “code completion” as users are working with application.properties or application.yml files.

The majority of the meta-data file is generated automatically at compile time by processing all items annotated with @ConfigurationProperties. However, it is possible to write part of the meta-data manually for corner cases or more advanced use cases.

B.1 Meta-data format

Configuration meta-data files are located inside jars under META-INF/spring-configuration-metadata.json They use a simple JSON format with items categorized under either “groups” or “properties” and additional values hint categorized under "hints":

{"groups": [
	{
		"name": "server",
		"type": "org.springframework.boot.autoconfigure.web.ServerProperties",
		"sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties"
	},
	{
		"name": "spring.jpa.hibernate",
		"type": "org.springframework.boot.autoconfigure.orm.jpa.JpaProperties$Hibernate",
		"sourceType": "org.springframework.boot.autoconfigure.orm.jpa.JpaProperties",
		"sourceMethod": "getHibernate()"
	}
	...
],"properties": [
	{
		"name": "server.port",
		"type": "java.lang.Integer",
		"sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties"
	},
	{
		"name": "server.servlet.path",
		"type": "java.lang.String",
		"sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties",
		"defaultValue": "/"
	},
	{
		  "name": "spring.jpa.hibernate.ddl-auto",
		  "type": "java.lang.String",
		  "description": "DDL mode. This is actually a shortcut for the \"hibernate.hbm2ddl.auto\" property.",
		  "sourceType": "org.springframework.boot.autoconfigure.orm.jpa.JpaProperties$Hibernate"
	}
	...
],"hints": [
	{
		"name": "spring.jpa.hibernate.ddl-auto",
		"values": [
			{
				"value": "none",
				"description": "Disable DDL handling."
			},
			{
				"value": "validate",
				"description": "Validate the schema, make no changes to the database."
			},
			{
				"value": "update",
				"description": "Update the schema if necessary."
			},
			{
				"value": "create",
				"description": "Create the schema and destroy previous data."
			},
			{
				"value": "create-drop",
				"description": "Create and then destroy the schema at the end of the session."
			}
		]
	}
]}

Each “property” is a configuration item that the user specifies with a given value. For example server.port and server.servlet.path might be specified in application.properties as follows:

server.port=9090
server.servlet.path=/home

The “groups” are higher level items that don’t themselves specify a value, but instead provide a contextual grouping for properties. For example the server.port and server.servlet.path properties are part of the server group.

[Note]Note

It is not required that every “property” has a “group”, some properties might just exist in their own right.

Finally, “hints” are additional information used to assist the user in configuring a given property. When configuring the spring.jpa.hibernate.ddl-auto property, a tool can use it to offer some auto-completion help for the none, validate, update, create and create-drop values.

B.1.1 Group Attributes

The JSON object contained in the groups array can contain the following attributes:

NameTypePurpose

name

String

The full name of the group. This attribute is mandatory.

type

String

The class name of the data type of the group. For example, if the group was based on a class annotated with @ConfigurationProperties the attribute would contain the fully qualified name of that class. If it was based on a @Bean method, it would be the return type of that method. The attribute may be omitted if the type is not known.

description

String

A short description of the group that can be displayed to users. May be omitted if no description is available. It is recommended that descriptions are a short paragraphs, with the first line providing a concise summary. The last line in the description should end with a period (.).

sourceType

String

The class name of the source that contributed this group. For example, if the group was based on a @Bean method annotated with @ConfigurationProperties this attribute would contain the fully qualified name of the @Configuration class containing the method. The attribute may be omitted if the source type is not known.

sourceMethod

String

The full name of the method (include parenthesis and argument types) that contributed this group. For example, the name of a @ConfigurationProperties annotated @Bean method. May be omitted if the source method is not known.

B.1.2 Property Attributes

The JSON object contained in the properties array can contain the following attributes:

NameTypePurpose

name

String

The full name of the property. Names are in lowercase dashed form (e.g. server.servlet.path). This attribute is mandatory.

type

String

The full signature of the data type of the property. For example, java.lang.String but also a full generic type such as java.util.Map<java.util.String,acme.MyEnum>. This attribute can be used to guide the user as to the types of values that they can enter. For consistency, the type of a primitive is specified using its wrapper counterpart, i.e. boolean becomes java.lang.Boolean. Note that this class may be a complex type that gets converted from a String as values are bound. May be omitted if the type is not known.

description

String

A short description of the group that can be displayed to users. May be omitted if no description is available. It is recommended that descriptions are a short paragraphs, with the first line providing a concise summary. The last line in the description should end with a period (.).

sourceType

String

The class name of the source that contributed this property. For example, if the property was from a class annotated with @ConfigurationProperties this attribute would contain the fully qualified name of that class. May be omitted if the source type is not known.

defaultValue

Object

The default value which will be used if the property is not specified. Can also be an array of value(s) if the type of the property is an array. May be omitted if the default value is not known.

deprecation

Deprecation

Specify if the property is deprecated. May be omitted if the field is not deprecated or if that information is not known. See below for more details.

The JSON object contained in the deprecation attribute of each properties element can contain the following attributes:

NameTypePurpose

level

String

The level of deprecation, can be either warning (default) or error. When a property has a warning deprecation level it should still be bound in the environment. When it has an error deprecation level however, the property is no longer managed and will not be bound.

reason

String

A short description of the reason why the property was deprecated. May be omitted if no reason is available. It is recommended that descriptions are a short paragraphs, with the first line providing a concise summary. The last line in the description should end with a period (.).

replacement

String

The full name of the property that is replacing this deprecated property. May be omitted if there is no replacement for this property.

[Note]Note

Prior to Spring Boot 1.3, a single deprecated boolean attribute can be used instead of the deprecation element. This is still supported in a deprecated fashion and should no longer be used. If no reason and replacement are available, an empty deprecation object should be set.

Deprecation can also be specified declaratively in code by adding the @DeprecatedConfigurationProperty annotation to the getter exposing the deprecated property. For instance, let’s assume the app.foo.target property was confusing and was renamed to app.foo.name

@ConfigurationProperties("app.foo")
public class FooProperties {

	private String name;

	public String getName() { ... }

	public void setName(String name) { ... }

	@DeprecatedConfigurationProperty(replacement = "app.foo.name")
	@Deprecated
	public String getTarget() {
		return getName();
	}

	@Deprecated
	public void setTarget(String target) {
		setName(target);
	}
}
[Note]Note

There is no way to set a level as warning is always assumed since code is still handling the property.

The code above makes sure that the deprecated property still works (delegating to the name property behind the scenes). Once the getTarget and setTarget methods can be removed from your public API, the automatic deprecation hint in the meta-data will go away as well. If you want to keep a hint, adding manual meta-data with an error deprecation level ensures that users are still informed about that property and is particularly useful when a replacement is provided.

B.1.3 Hint Attributes

The JSON object contained in the hints array can contain the following attributes:

NameTypePurpose

name

String

The full name of the property that this hint refers to. Names are in lowercase dashed form (e.g. server.servlet.path). If the property refers to a map (e.g. system.contexts) the hint either applies to the keys of the map (system.context.keys) or the values (system.context.values). This attribute is mandatory.

values

ValueHint[]

A list of valid values as defined by the ValueHint object (see below). Each entry defines the value and may have a description

providers

ValueProvider[]

A list of providers as defined by the ValueProvider object (see below). Each entry defines the name of the provider and its parameters, if any.

The JSON object contained in the values attribute of each hint element can contain the following attributes:

NameTypePurpose

value

Object

A valid value for the element to which the hint refers to. Can also be an array of value(s) if the type of the property is an array. This attribute is mandatory.

description

String

A short description of the value that can be displayed to users. May be omitted if no description is available. It is recommended that descriptions are a short paragraphs, with the first line providing a concise summary. The last line in the description should end with a period (.).

The JSON object contained in the providers attribute of each hint element can contain the following attributes:

NameTypePurpose

name

String

The name of the provider to use to offer additional content assistance for the element to which the hint refers to.

parameters

JSON object

Any additional parameter that the provider supports (check the documentation of the provider for more details).

B.1.4 Repeated meta-data items

It is perfectly acceptable for “property” and “group” objects with the same name to appear multiple times within a meta-data file. For example, you could bind two separate classes to the same prefix, with each potentially offering overlap of property names. While this is not supposed to be a frequent scenario, consumers of meta-data should take care to ensure that they support such scenarios.

B.2 Providing manual hints

To improve the user experience and further assist the user in configuring a given property, you can provide additional meta-data that:

  1. Describes the list of potential values for a property.
  2. Associates 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.

B.2.1 Value hint

The name attribute of each hint refers to the name of a property. In the initial example above, we provide 5 values for the spring.jpa.hibernate.ddl-auto property: none, validate, update, create and create-drop. Each value may have a description as well.

If your property is of type Map, you can provide hints for both the keys and the values (but not for the map itself). The special .keys and .values suffixes must be used to refer to the keys and the values respectively.

Let’s assume a foo.contexts that maps magic String values to an integer:

@ConfigurationProperties("foo")
public class FooProperties {

	private Map<String,Integer> contexts;
	// getters and setters
}

The magic values are foo and bar for instance. In order to offer additional content assistance for the keys, you could add the following to the manual meta-data of the module:

{"hints": [
	{
		"name": "foo.contexts.keys",
		"values": [
			{
				"value": "foo"
			},
			{
				"value": "bar"
			}
		]
	}
]}
[Note]Note

Of course, you should have an Enum for those two values instead. This is by far the most effective approach to auto-completion if your IDE supports it.

B.2.2 Value provider

Providers are a powerful way of attaching semantics to a property. We define in the section below the official providers that you can use for your own hints. Bare in mind however that your favorite IDE may implement some of these or none of them. It could eventually provide its own as well.

[Note]Note

As this is a new feature, IDE vendors will have to catch up with this new feature.

The table below summarizes the list of supported providers:

NameDescription

any

Permit any additional value to be provided.

class-reference

Auto-complete the classes available in the project. Usually constrained by a base class that is specified via the target parameter.

handle-as

Handle the property as if it was defined by the type defined via the mandatory target parameter.

logger-name

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

spring-bean-reference

Auto-complete the available bean names in the current project. Usually constrained by a base class that is specified via the target parameter.

spring-profile-name

Auto-complete the available Spring profile names in the project.

[Tip]Tip

No more than one provider can be active for a given property but you can specify several providers if they can all manage the property in some ways. Make sure to place the most powerful provider first as the IDE must use the first one in the JSON section it can handle. If no provider for a given property is supported, no special content assistance is provided either.

Any

The any provider permits any additional values to be provided. Regular value validation based on the property type should be applied if this is supported.

This provider will be typically used if you have a list of values and any extra values are still to be considered as valid.

The example below offers on and off as auto-completion values for system.state; any other value is also allowed:

{"hints": [
	{
		"name": "system.state",
		"values": [
			{
				"value": "on"
			},
			{
				"value": "off"
			}
		],
		"providers": [
			{
				"name": "any"
			}
		]
	}
]}

Class reference

The class-reference provider auto-completes classes available in the project. This provider supports these parameters:

ParameterTypeDefault valueDescription

target

String (Class)

none

The fully qualified name of the class that should be assignable to the chosen value. Typically used to filter out non candidate classes. Note that this information can be provided by the type itself by exposing a class with the appropriate upper bound.

concrete

boolean

true

Specify if only concrete classes are to be considered as valid candidates.

The meta-data snippet below corresponds to the standard server.servlet.jsp.class-name property that defines the JspServlet class name to use:

{"hints": [
	{
		"name": "server.servlet.jsp.class-name",
		"providers": [
			{
				"name": "class-reference",
				"parameters": {
					"target": "javax.servlet.http.HttpServlet"
				}
			}
		]
	}
]}

Handle As

The handle-as provider allows you to substitute the type of the property to a more high-level type. This typically happens when the property has a java.lang.String type because you don’t want your configuration classes to rely on classes that may not be on the classpath. This provider supports these parameters:

ParameterTypeDefault valueDescription

target

String (Class)

none

The fully qualified name of the type to consider for the property. This parameter is mandatory.

The following types can be used:

  • Any java.lang.Enum that lists the possible values for the property (By all means, try to define the property with the Enum type instead as no further hint should be required for the IDE to auto-complete the values).
  • java.nio.charset.Charset: auto-completion of charset/encoding values (e.g. UTF-8)
  • java.util.Locale: auto-completion of locales (e.g. en_US)
  • org.springframework.util.MimeType: auto-completion of content type values (e.g. text/plain)
  • org.springframework.core.io.Resource: auto-completion of Spring’s Resource abstraction to refer to a file on the filesystem or on the classpath. (e.g. classpath:/foo.properties)
[Note]Note

If multiple values can be provided, use a Collection or Array type to teach the IDE about it.

The meta-data snippet below corresponds to the standard spring.liquibase.change-log property that defines the path to the changelog to use. It is actually used internally as a org.springframework.core.io.Resource but cannot be exposed as such as we need to keep the original String value to pass it to the Liquibase API.

{"hints": [
	{
		"name": "spring.liquibase.change-log",
		"providers": [
			{
				"name": "handle-as",
				"parameters": {
					"target": "org.springframework.core.io.Resource"
				}
			}
		]
	}
]}

Logger name

The logger-name provider auto-completes valid logger names. Typically, package and class names available in the current project can be auto-completed. Specific frameworks may have extra magic logger names that could be supported as well.

Since a logger name can be any arbitrary name, really, this provider should allow any value but could highlight valid packages and class names that are not available in the project’s classpath.

The meta-data snippet below corresponds to the standard logging.level property, keys are logger names and values correspond to the standard log levels or any custom level:

{"hints": [
	{
		"name": "logging.level.keys",
		"values": [
			{
				"value": "root",
				"description": "Root logger used to assign the default logging level."
			}
		],
		"providers": [
			{
				"name": "logger-name"
			}
		]
	},
	{
		"name": "logging.level.values",
		"values": [
			{
				"value": "trace"
			},
			{
				"value": "debug"
			},
			{
				"value": "info"
			},
			{
				"value": "warn"
			},
			{
				"value": "error"
			},
			{
				"value": "fatal"
			},
			{
				"value": "off"
			}

		],
		"providers": [
			{
				"name": "any"
			}
		]
	}
]}

Spring bean reference

The spring-bean-reference provider auto-completes the beans that are defined in the configuration of the current project. This provider supports these parameters:

ParameterTypeDefault valueDescription

target

String (Class)

none

The fully qualified name of the bean class that should be assignable to the candidate. Typically used to filter out non candidate beans.

The meta-data snippet below corresponds to the standard spring.jmx.server property that defines the name of the MBeanServer bean to use:

{"hints": [
	{
		"name": "spring.jmx.server",
		"providers": [
			{
				"name": "spring-bean-reference",
				"parameters": {
					"target": "javax.management.MBeanServer"
				}
			}
		]
	}
]}
[Note]Note

The binder is not aware of the meta-data so if you provide that hint, you will still need to transform the bean name into an actual Bean reference using the ApplicationContext.

Spring profile name

The spring-profile-name provider auto-completes the Spring profiles that are defined in the configuration of the current project.

The meta-data snippet below corresponds to the standard spring.profiles.active property that defines the name of the Spring profile(s) to enable:

{"hints": [
	{
		"name": "spring.profiles.active",
		"providers": [
			{
				"name": "spring-profile-name"
			}
		]
	}
]}

B.3 Generating your own meta-data using the annotation processor

You can easily generate your own configuration meta-data file from items annotated with @ConfigurationProperties by using the spring-boot-configuration-processor jar. The jar includes a Java annotation processor which is invoked as your project is compiled. To use the processor, simply include spring-boot-configuration-processor as an optional dependency, for example with Maven you would add:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-configuration-processor</artifactId>
	<optional>true</optional>
</dependency>

With Gradle, you can use the propdeps-plugin and specify:

dependencies {
	optional "org.springframework.boot:spring-boot-configuration-processor"
}

compileJava.dependsOn(processResources)
[Note]Note

You need to add compileJava.dependsOn(processResources) to your build to ensure that resources are processed before code is compiled. Without this directive any additional-spring-configuration-metadata.json files will not be processed.

The processor will pick up both classes and methods that are annotated with @ConfigurationProperties. The Javadoc for field values within configuration classes will be used to populate the description attribute.

[Note]Note

You should only use simple text with @ConfigurationProperties field Javadoc since they are not processed before being added to the JSON.

Properties are discovered via the presence of standard getters and setters with special handling for collection types (that will be detected even if only a getter is present). The annotation processor also supports the use of the @Data, @Getter and @Setter lombok annotations.

[Note]Note

If you are using AspectJ in your project, you need to make sure that the annotation processor only runs once. There are several ways to do this: with Maven, you can configure the maven-apt-plugin explicitly and add the dependency to the annotation processor only there. You could also let the AspectJ plugin run all the processing and disable annotation processing in the maven-compiler-plugin configuration:

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-compiler-plugin</artifactId>
	<configuration>
		<proc>none</proc>
	</configuration>
</plugin>

B.3.1 Nested properties

The annotation processor will automatically consider inner classes as nested properties. For example, the following class:

@ConfigurationProperties(prefix="server")
public class ServerProperties {

	private String name;

	private Host host;

	// ... getter and setters

	private static class Host {

		private String ip;

		private int port;

		// ... getter and setters

	}

}

Will produce meta-data information for server.name, server.host.ip and server.host.port properties. You can use the @NestedConfigurationProperty annotation on a field to indicate that a regular (non-inner) class should be treated as if it were nested.

[Tip]Tip

This has no effect on collections and maps as those types are automatically identified and a single meta-data property is generated for each of them.

B.3.2 Adding additional meta-data

Spring Boot’s configuration file handling is quite flexible; and it is often the case that properties may exist that are not bound to a @ConfigurationProperties bean. You may also need to tune some attributes of an existing key. To support such cases and allow you to provide custom "hints", the annotation processor will automatically merge items from META-INF/additional-spring-configuration-metadata.json into the main meta-data file.

If you refer to a property that has been detected automatically, the description, default value and deprecation information are overridden if specified. If the manual property declaration is not identified in the current module, it is added as a brand new property.

The format of the additional-spring-configuration-metadata.json file is exactly the same as the regular spring-configuration-metadata.json. The additional properties file is optional, if you don’t have any additional properties, simply don’t add it.