[[appendix.configuration-metadata.annotation-processor]]
= Generating Your Own Metadata by Using the Annotation Processor

You can easily generate your own configuration metadata file from items annotated with javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] by using the `spring-boot-configuration-processor` jar.
The jar includes a Java annotation processor which is invoked as your project is compiled.



[[appendix.configuration-metadata.annotation-processor.configuring]]
== Configuring the Annotation Processor

When building with Maven, configure the compiler plugin (3.12.0 or later) to add `spring-boot-configuration-processor` to the annotation processor paths:

[source,xml]
----
<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<annotationProcessorPaths>
						<path>
							<groupId>org.springframework.boot</groupId>
							<artifactId>spring-boot-configuration-processor</artifactId>
						</path>
					</annotationProcessorPaths>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>
----

With Gradle, a dependency should be declared in the `annotationProcessor` configuration, as shown in the following example:

[source,gradle]
----
dependencies {
	annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
}
----

If you are using an `additional-spring-configuration-metadata.json` file, the `compileJava` task should be configured to depend on the `processResources` task, as shown in the following example:

[source,gradle]
----
tasks.named('compileJava') {
	inputs.files(tasks.named('processResources'))
}
----

This dependency ensures that the additional metadata is available when the annotation processor runs during compilation.

[NOTE]
====
If you are using AspectJ in your project, you need to make sure that the annotation processor runs only 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, as follows:

[source,xml]
----
<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-compiler-plugin</artifactId>
	<configuration>
		<proc>none</proc>
	</configuration>
</plugin>
----
====

[NOTE]
====
If you are using Lombok in your project, you need to make sure that its annotation processor runs before `spring-boot-configuration-processor`.
To do so with Maven, list the annotation processors in the required order using the `annotationProcessors` attribute of the Maven compiler plugin.
With Gradle, declare the dependencies in the `annotationProcessor` configuration in the required order.
====



[[appendix.configuration-metadata.annotation-processor.automatic-metadata-generation]]
== Automatic Metadata Generation

The processor picks up both classes and methods that are annotated with javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation]. It also picks classes that are annotated with javadoc:org.springframework.boot.context.properties.ConfigurationPropertiesSource[format=annotation]

NOTE: Custom annotations that are meta-annotated with either of those annotations are not supported.

If the class has a single parameterized constructor, one property is created per constructor parameter, unless the constructor is annotated with javadoc:org.springframework.beans.factory.annotation.Autowired[format=annotation].
If the class has a constructor explicitly annotated with javadoc:org.springframework.boot.context.properties.bind.ConstructorBinding[format=annotation], one property is created per constructor parameter for that constructor.
Otherwise, properties are discovered through the presence of standard getters and setters with special handling for collection and map types (that is detected even if only a getter is present).
The annotation processor also supports the use of the javadoc:{url-lombok-javadoc}/lombok.Data[format=annotation], javadoc:{url-lombok-javadoc}/lombok.Value[format=annotation], javadoc:{url-lombok-javadoc}/lombok.Getter[format=annotation], and javadoc:{url-lombok-javadoc}/lombok.Setter[format=annotation] lombok annotations.

Consider the following example:

include-code::MyServerProperties[]

This exposes three properties where `my.server.name` has no default and `my.server.ip` and `my.server.port` defaults to `"127.0.0.1"` and `9797` respectively.
The Javadoc on fields is used to populate the `description` attribute.
For instance, the description of `my.server.ip` is "IP address to listen to.".

The `description` attribute can only be populated when the type is available as source code that is being compiled.
It will not be populated when the type is only available as a compiled class from a dependency.
For such cases, you can xref:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation.source[source the metadata] or xref:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.adding-additional-metadata[provide manual entries].

NOTE: You should only use plain text with javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] field Javadoc, since they are not processed before being added to the JSON.

If you use javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] with record class then record components' descriptions should be provided via class-level Javadoc tag `@param` (there are no explicit instance fields in record classes to put regular field-level Javadocs on).

The annotation processor applies a number of heuristics to extract the default value from the source model.
Default values can only be extracted when the type is available as source code that is being compiled.
They will not be extracted when the type is only available as a compiled class from a dependency.
Furthermore, default values have to be provided statically.
In particular, do not refer to a constant defined in another class.
Also, the annotation processor cannot auto-detect default values for ``Collections``s.

For cases where the default value could not be detected, xref:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.adding-additional-metadata[manual metadata] should be provided.
Consider the following example:

include-code::MyMessagingProperties[]

In order to document default values for properties in the class above, you could add the following content to xref:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.adding-additional-metadata[the manual metadata of the module]:

[source,json]
----
{"properties": [
	{
		"name": "my.messaging.addresses",
		"defaultValue": ["a", "b"]
	},
	{
		"name": "my.messaging.container-type",
		"defaultValue": "simple"
	}
]}
----

NOTE: Only the `name` of the property is required to document additional metadata for existing properties.



[[appendix.configuration-metadata.annotation-processor.automatic-metadata-generation.nested-properties]]
=== Nested Properties

The annotation processor automatically considers inner classes as nested properties.
Rather than documenting the `ip` and `port` at the root of the namespace, we could create a sub-namespace for it.
Consider the updated example:

include-code::MyServerProperties[]

The preceding example produces metadata information for `my.server.name`, `my.server.host.ip`, and `my.server.host.port` properties.
You can use the javadoc:org.springframework.boot.context.properties.NestedConfigurationProperty[format=annotation] annotation on a field or a getter method to indicate that a regular (non-inner) class should be treated as if it were nested.

TIP: This has no effect on collections and maps, as those types are automatically identified, and a single metadata property is generated for each of them.



[[appendix.configuration-metadata.annotation-processor.automatic-metadata-generation.source]]
=== Configuration Properties Source

If a type located in another module is used in a javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation]-annotated type, some metadata elements cannot be discovered automatically.
Reusing the example above, if `Host` is located in another module, full metadata is not available as the annotation processor does not have access to the source of `Host`.

To handle this use case, add the annotation processor in the module that contains the `Host` type and annotate it with javadoc:org.springframework.boot.context.properties.ConfigurationPropertiesSource[format=annotation]:

include-code::Host[]

This generates the metadata for `Host` in `META-INF/spring/configuration-metadata/com.example.Host.json` and is reused automatically by the annotation processor when it handles such type.

You can also annotate a parent class located in another module that a javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation]-annotated type extends from.

TIP: If you need to reuse metadata for a type that you do not control, create a file named with the pattern above and it will be used as long as it is available on the classpath.



[[appendix.configuration-metadata.annotation-processor.adding-additional-metadata]]
== Adding Additional Metadata

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 javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] bean.
You may also need to tune some attributes of an existing key or to ignore the key altogether.
To support such cases and let you provide custom "hints", the annotation processor automatically merges items from `META-INF/additional-spring-configuration-metadata.json` into the main metadata file.

When generating source metadata for a type, you can also craft custom metadata for that type, for example `com.example.SomeType`, in `META-INF/spring/configuration/metadata/com.example.SomeType.json`.

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 new property.

The format of the additional metadata file is exactly the same as the regular `spring-configuration-metadata.json`.
The items contained in the "`ignored.properties`" section are removed from the "`properties`" section of the generated  `spring-configuration-metadata.json` file.

The additional properties file is optional.
If you do not have any additional properties, do not add the file.
