Migrate spring-boot-docs to Antora

See gh-33766
This commit is contained in:
Phillip Webb
2024-03-19 21:48:08 -07:00
parent 8ee20c8dae
commit 8dd89c1ac7
202 changed files with 6844 additions and 6593 deletions

View File

@@ -0,0 +1,149 @@
[[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 `@ConfigurationProperties` 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
To use the processor, include a dependency on `spring-boot-configuration-processor`.
With Maven the dependency should be declared as optional, as shown in the following example:
[source,xml]
----
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
----
With Gradle, the 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, you can list the annotation processors in the right order using the `annotationProcessors` attribute of the Maven compiler plugin.
If you are not using this attribute, and annotation processors are picked up by the dependencies available on the classpath, make sure that the `lombok` dependency is defined before the `spring-boot-configuration-processor` dependency.
====
[[appendix.configuration-metadata.annotation-processor.automatic-metadata-generation]]
== Automatic Metadata Generation
The processor picks up both classes and methods that are annotated with `@ConfigurationProperties`.
If the class has a single parameterized constructor, one property is created per constructor parameter, unless the constructor is annotated with `@Autowired`.
If the class has a constructor explicitly annotated with `@ConstructorBinding`, 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 `@Data`, `@Value`, `@Getter`, and `@Setter` 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.".
NOTE: You should only use plain text with `@ConfigurationProperties` field Javadoc, since they are not processed before being added to the JSON.
The annotation processor applies a number of heuristics to extract the default value from the source model.
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 ``Enum``s and ``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 `@NestedConfigurationProperty` annotation on a field 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.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 `@ConfigurationProperties` bean.
You may also need to tune some attributes of an existing key.
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.
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-spring-configuration-metadata.json` file is exactly the same as the regular `spring-configuration-metadata.json`.
The additional properties file is optional.
If you do not have any additional properties, do not add the file.

View File

@@ -0,0 +1,300 @@
[[appendix.configuration-metadata.format]]
= Metadata Format
Configuration metadata files are located inside jars under `META-INF/spring-configuration-metadata.json`.
They use a JSON format with items categorized under either "`groups`" or "`properties`" and additional values hints categorized under "hints", as shown in the following example:
[source,json]
----
{"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.address",
"type": "java.net.InetAddress",
"sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties"
},
{
"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.address` might be specified in your `application.properties`/`application.yaml`, as follows:
[configprops,yaml]
----
server:
port: 9090
address: 127.0.0.1
----
The "`groups`" are higher level items that do not themselves specify a value but instead provide a contextual grouping for properties.
For example, the `server.port` and `server.address` properties are part of the `server` group.
NOTE: It is not required that every "`property`" has a "`group`".
Some properties might exist in their own right.
Finally, "`hints`" are additional information used to assist the user in configuring a given property.
For example, when a developer is configuring the configprop:spring.jpa.hibernate.ddl-auto[] property, a tool can use the hints to offer some auto-completion help for the `none`, `validate`, `update`, `create`, and `create-drop` values.
[[appendix.configuration-metadata.format.group]]
== Group Attributes
The JSON object contained in the `groups` array can contain the attributes shown in the following table:
[cols="1,1,4"]
|===
| Name | Type | Purpose
| `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 were based on a class annotated with `@ConfigurationProperties`, the attribute would contain the fully qualified name of that class.
If it were based on a `@Bean` method, it would be the return type of that method.
If the type is not known, the attribute may be omitted.
| `description`
| String
| A short description of the group that can be displayed to users.
If no description is available, it may be omitted.
It is recommended that descriptions be 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 were based on a `@Bean` method annotated with `@ConfigurationProperties`, this attribute would contain the fully qualified name of the `@Configuration` class that contains the method.
If the source type is not known, the attribute may be omitted.
| `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).
If the source method is not known, it may be omitted.
|===
[[appendix.configuration-metadata.format.property]]
== Property Attributes
The JSON object contained in the `properties` array can contain the attributes described in the following table:
[cols="1,1,4"]
|===
| Name | Type | Purpose
| `name`
| String
| The full name of the property.
Names are in lower-case period-separated form (for example, `server.address`).
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.lang.String,com.example.MyEnum>`).
You can use this attribute to guide the user as to the types of values that they can enter.
For consistency, the type of a primitive is specified by using its wrapper counterpart (for example, `boolean` becomes `java.lang.Boolean`).
Note that this class may be a complex type that gets converted from a `String` as values are bound.
If the type is not known, it may be omitted.
| `description`
| String
| A short description of the property that can be displayed to users.
If no description is available, it may be omitted.
It is recommended that descriptions be 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 were from a class annotated with `@ConfigurationProperties`, this attribute would contain the fully qualified name of that class.
If the source type is unknown, it may be omitted.
| `defaultValue`
| Object
| The default value, which is used if the property is not specified.
If the type of the property is an array, it can be an array of value(s).
If the default value is unknown, it may be omitted.
| `deprecation`
| Deprecation
| Specify whether the property is deprecated.
If the field is not deprecated or if that information is not known, it may be omitted.
The next table offers more detail about the `deprecation` attribute.
|===
The JSON object contained in the `deprecation` attribute of each `properties` element can contain the following attributes:
[cols="1,1,4"]
|===
| Name | Type | Purpose
| `level`
| String
| The level of deprecation, which can be either `warning` (the default) or `error`.
When a property has a `warning` deprecation level, it should still be bound in the environment.
However, when it has an `error` deprecation level, the property is no longer managed and is not bound.
| `reason`
| String
| A short description of the reason why the property was deprecated.
If no reason is available, it may be omitted.
It is recommended that descriptions be 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 _replaces_ this deprecated property.
If there is no replacement for this property, it may be omitted.
| `since`
| String
| The version in which the property became deprecated.
Can be omitted.
|===
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, assume that the `my.app.target` property was confusing and was renamed to `my.app.name`.
The following example shows how to handle that situation:
include-code::MyProperties[]
NOTE: There is no way to set a `level`.
`warning` is always assumed, since code is still handling the property.
The preceding code 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 metadata goes away as well.
If you want to keep a hint, adding manual metadata with an `error` deprecation level ensures that users are still informed about that property.
Doing so is particularly useful when a `replacement` is provided.
[[appendix.configuration-metadata.format.hints]]
== Hint Attributes
The JSON object contained in the `hints` array can contain the attributes shown in the following table:
[cols="1,1,4"]
|===
| Name | Type | Purpose
| `name`
| String
| The full name of the property to which this hint refers.
Names are in lower-case period-separated form (such as `spring.mvc.servlet.path`).
If the property refers to a map (such as `system.contexts`), the hint either applies to the _keys_ of the map (`system.contexts.keys`) or the _values_ (`system.contexts.values`) of the map.
This attribute is mandatory.
| `values`
| ValueHint[]
| A list of valid values as defined by the `ValueHint` object (described in the next table).
Each entry defines the value and may have a description.
| `providers`
| ValueProvider[]
| A list of providers as defined by the `ValueProvider` object (described later in this document).
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 attributes described in the following table:
[cols="1,1,4"]
|===
| Name | Type | Purpose
| `value`
| Object
| A valid value for the element to which the hint refers.
If the type of the property is an array, it can also be an array of value(s).
This attribute is mandatory.
| `description`
| String
| A short description of the value that can be displayed to users.
If no description is available, it may be omitted.
It is recommended that descriptions be 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 attributes described in the following table:
[cols="1,1,4"]
|===
|Name | Type |Purpose
| `name`
| String
| The name of the provider to use to offer additional content assistance for the element to which the hint refers.
| `parameters`
| JSON object
| Any additional parameter that the provider supports (check the documentation of the provider for more details).
|===
[[appendix.configuration-metadata.format.repeated-items]]
== Repeated Metadata Items
Objects with the same "`property`" and "`group`" name can appear multiple times within a metadata file.
For example, you could bind two separate classes to the same prefix, with each having potentially overlapping property names.
While the same names appearing in the metadata multiple times should not be common, consumers of metadata should take care to ensure that they support it.

View File

@@ -0,0 +1,9 @@
[appendix]
[[appendix.configuration-metadata]]
= Configuration Metadata
Spring Boot jars include metadata files that provide details of all supported configuration properties.
The files are designed to let IDE developers offer contextual help and "`code completion`" as users are working with `application.properties` or `application.yaml` files.
The majority of the metadata file is generated automatically at compile time by processing all items annotated with `@ConfigurationProperties`.
However, it is possible to xref:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.adding-additional-metadata[write part of the metadata manually] for corner cases or more advanced use cases.

View File

@@ -0,0 +1,375 @@
[[appendix.configuration-metadata.manual-hints]]
= Providing Manual Hints
To improve the user experience and further assist the user in configuring a given property, you can provide additional metadata that:
* Describes the list of potential values for a property.
* 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.
[[appendix.configuration-metadata.manual-hints.value-hint]]
== Value Hint
The `name` attribute of each hint refers to the `name` of a property.
In the xref:configuration-metadata/format.adoc[initial example shown earlier], we provide five 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 refer to the keys and the values, respectively.
Assume a `my.contexts` maps magic `String` values to an integer, as shown in the following example:
include-code::MyProperties[]
The magic values are (in this example) are `sample1` and `sample2`.
In order to offer additional content assistance for the keys, you could add the following JSON to xref:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.adding-additional-metadata[the manual metadata of the module]:
[source,json]
----
{"hints": [
{
"name": "my.contexts.keys",
"values": [
{
"value": "sample1"
},
{
"value": "sample2"
}
]
}
]}
----
TIP: We recommend that you use an `Enum` for those two values instead.
If your IDE supports it, this is by far the most effective approach to auto-completion.
[[appendix.configuration-metadata.manual-hints.value-providers]]
== Value Providers
Providers are a powerful way to attach semantics to a property.
In this section, we define the official providers that you can use for your own hints.
However, your favorite IDE may implement some of these or none of them.
Also, it could eventually provide its own.
NOTE: As this is a new feature, IDE vendors must catch up with how it works.
Adoption times naturally vary.
The following table summarizes the list of supported providers:
[cols="2,4"]
|===
| Name | Description
| `any`
| Permits any additional value to be provided.
| `class-reference`
| Auto-completes the classes available in the project.
Usually constrained by a base class that is specified by the `target` parameter.
| `handle-as`
| Handles the property as if it were defined by the type defined by the mandatory `target` parameter.
| `logger-name`
| Auto-completes valid logger names and xref:reference:features/logging.adoc#features.logging.log-groups[logger groups].
Typically, package and class names available in the current project can be auto-completed as well as defined groups.
| `spring-bean-reference`
| Auto-completes the available bean names in the current project.
Usually constrained by a base class that is specified by the `target` parameter.
| `spring-profile-name`
| Auto-completes the available Spring profile names in the project.
|===
TIP: Only one provider can be active for a given property, but you can specify several providers if they can all manage the property _in some way_.
Make sure to place the most powerful provider first, as the IDE must use the first one in the JSON section that it can handle.
If no provider for a given property is supported, no special content assistance is provided, either.
[[appendix.configuration-metadata.manual-hints.value-providers.any]]
=== Any
The special **any** provider value permits any additional values to be provided.
Regular value validation based on the property type should be applied if this is supported.
This provider is typically used if you have a list of values and any extra values should still be considered as valid.
The following example offers `on` and `off` as auto-completion values for `system.state`:
[source,json]
----
{"hints": [
{
"name": "system.state",
"values": [
{
"value": "on"
},
{
"value": "off"
}
],
"providers": [
{
"name": "any"
}
]
}
]}
----
Note that, in the preceding example, any other value is also allowed.
[[appendix.configuration-metadata.manual-hints.value-providers.class-reference]]
=== Class Reference
The **class-reference** provider auto-completes classes available in the project.
This provider supports the following parameters:
[cols="1,1,2,4"]
|===
| Parameter | Type | Default value | Description
| `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 whether only concrete classes are to be considered as valid candidates.
|===
The following metadata snippet corresponds to the standard `server.servlet.jsp.class-name` property that defines the `JspServlet` class name to use:
[source,json]
----
{"hints": [
{
"name": "server.servlet.jsp.class-name",
"providers": [
{
"name": "class-reference",
"parameters": {
"target": "jakarta.servlet.http.HttpServlet"
}
}
]
}
]}
----
[[appendix.configuration-metadata.manual-hints.value-providers.handle-as]]
=== Handle As
The **handle-as** provider lets you 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 do not want your configuration classes to rely on classes that may not be on the classpath.
This provider supports the following parameters:
[cols="1,1,2,4"]
|===
| Parameter | Type | Default value | Description
| **`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`: Lists the possible values for the property.
(We recommend defining the property with the `Enum` type, as no further hint should be required for the IDE to auto-complete the values)
* `java.nio.charset.Charset`: Supports auto-completion of charset/encoding values (such as `UTF-8`)
* `java.util.Locale`: auto-completion of locales (such as `en_US`)
* `org.springframework.util.MimeType`: Supports auto-completion of content type values (such as `text/plain`)
* `org.springframework.core.io.Resource`: Supports auto-completion of Springs Resource abstraction to refer to a file on the filesystem or on the classpath (such as `classpath:/sample.properties`)
TIP: If multiple values can be provided, use a `Collection` or _Array_ type to teach the IDE about it.
The following metadata snippet 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, because we need to keep the original String value to pass it to the Liquibase API.
[source,json]
----
{"hints": [
{
"name": "spring.liquibase.change-log",
"providers": [
{
"name": "handle-as",
"parameters": {
"target": "org.springframework.core.io.Resource"
}
}
]
}
]}
----
[[appendix.configuration-metadata.manual-hints.value-providers.logger-name]]
=== Logger Name
The **logger-name** provider auto-completes valid logger names and xref:reference:features/logging.adoc#features.logging.log-groups[logger groups].
Typically, package and class names available in the current project can be auto-completed.
If groups are enabled (default) and if a custom logger group is identified in the configuration, auto-completion for it should be provided.
Specific frameworks may have extra magic logger names that can be supported as well.
This provider supports the following parameters:
[cols="1,1,2,4"]
|===
| Parameter | Type | Default value | Description
| `group`
| `boolean`
| `true`
| Specify whether known groups should be considered.
|===
Since a logger name can be any arbitrary name, this provider should allow any value but could highlight valid package and class names that are not available in the project's classpath.
The following metadata snippet corresponds to the standard `logging.level` property.
Keys are _logger names_, and values correspond to the standard log levels or any custom level.
As Spring Boot defines a few logger groups out-of-the-box, dedicated value hints have been added for those.
[source,json]
----
{"hints": [
{
"name": "logging.level.keys",
"values": [
{
"value": "root",
"description": "Root logger used to assign the default logging level."
},
{
"value": "sql",
"description": "SQL logging group including Hibernate SQL logger."
},
{
"value": "web",
"description": "Web logging group including codecs."
}
],
"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"
}
]
}
]}
----
[[appendix.configuration-metadata.manual-hints.value-providers.spring-bean-reference]]
=== 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 the following parameters:
[cols="1,1,2,4"]
|===
| Parameter | Type | Default value | Description
| `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 following metadata snippet corresponds to the standard `spring.jmx.server` property that defines the name of the `MBeanServer` bean to use:
[source,json]
----
{"hints": [
{
"name": "spring.jmx.server",
"providers": [
{
"name": "spring-bean-reference",
"parameters": {
"target": "javax.management.MBeanServer"
}
}
]
}
]}
----
NOTE: The binder is not aware of the metadata.
If you provide that hint, you still need to transform the bean name into an actual Bean reference using by the `ApplicationContext`.
[[appendix.configuration-metadata.manual-hints.value-providers.spring-profile-name]]
=== Spring Profile Name
The **spring-profile-name** provider auto-completes the Spring profiles that are defined in the configuration of the current project.
The following metadata snippet corresponds to the standard `spring.profiles.active` property that defines the name of the Spring profile(s) to enable:
[source,json]
----
{"hints": [
{
"name": "spring.profiles.active",
"providers": [
{
"name": "spring-profile-name"
}
]
}
]}
----

View File

@@ -0,0 +1,10 @@
[[appendix.executable-jar.alternatives]]
= Alternative Single Jar Solutions
If the preceding restrictions mean that you cannot use Spring Boot Loader, consider the following alternatives:
* https://maven.apache.org/plugins/maven-shade-plugin/[Maven Shade Plugin]
* http://www.jdotsoft.com/JarClassLoader.php[JarClassLoader]
* https://sourceforge.net/projects/one-jar/[OneJar]
* https://imperceptiblethoughts.com/shadow/[Gradle Shadow Plugin]

View File

@@ -0,0 +1,8 @@
[appendix]
[[appendix.executable-jar]]
= The Executable Jar Format
The `spring-boot-loader` modules lets Spring Boot support executable jar and war files.
If you use the Maven plugin or the Gradle plugin, executable jars are automatically generated, and you generally do not need to know the details of how they work.
If you need to create executable jars from a different build system or if you are just curious about the underlying technology, this appendix provides some background.

View File

@@ -0,0 +1,36 @@
[[appendix.executable-jar.jarfile-class]]
= Spring Boot's "`NestedJarFile`" Class
The core class used to support loading nested jars is `org.springframework.boot.loader.jar.NestedJarFile`.
It lets you load jar content from nested child jar data.
When first loaded, the location of each `JarEntry` is mapped to a physical file offset of the outer jar, as shown in the following example:
[source]
----
myapp.jar
+-------------------+-------------------------+
| /BOOT-INF/classes | /BOOT-INF/lib/mylib.jar |
|+-----------------+||+-----------+----------+|
|| A.class ||| B.class | C.class ||
|+-----------------+||+-----------+----------+|
+-------------------+-------------------------+
^ ^ ^
0063 3452 3980
----
The preceding example shows how `A.class` can be found in `/BOOT-INF/classes` in `myapp.jar` at position `0063`.
`B.class` from the nested jar can actually be found in `myapp.jar` at position `3452`, and `C.class` is at position `3980`.
Armed with this information, we can load specific nested entries by seeking to the appropriate part of the outer jar.
We do not need to unpack the archive, and we do not need to read all entry data into memory.
[[appendix.executable-jar.jarfile-class.compatibility]]
== Compatibility With the Standard Java "`JarFile`"
Spring Boot Loader strives to remain compatible with existing code and libraries.
`org.springframework.boot.loader.jar.NestedJarFile` extends from `java.util.jar.JarFile` and should work as a drop-in replacement.
Nested JAR URLs of the form `jar:nested:/path/myjar.jar/!BOOT-INF/lib/mylib.jar!/B.class` are supported and open a connection compatible with `java.net.JarURLConnection`.
These can be used with Java's `URLClassLoader`.

View File

@@ -0,0 +1,41 @@
[[appendix.executable-jar.launching]]
= Launching Executable Jars
The `org.springframework.boot.loader.launch.Launcher` class is a special bootstrap class that is used as an executable jar's main entry point.
It is the actual `Main-Class` in your jar file, and it is used to setup an appropriate `ClassLoader` and ultimately call your `main()` method.
There are three launcher subclasses (`JarLauncher`, `WarLauncher`, and `PropertiesLauncher`).
Their purpose is to load resources (`.class` files and so on) from nested jar files or war files in directories (as opposed to those explicitly on the classpath).
In the case of `JarLauncher` and `WarLauncher`, the nested paths are fixed.
`JarLauncher` looks in `BOOT-INF/lib/`, and `WarLauncher` looks in `WEB-INF/lib/` and `WEB-INF/lib-provided/`.
You can add extra jars in those locations if you want more.
The `PropertiesLauncher` looks in `BOOT-INF/lib/` in your application archive by default.
You can add additional locations by setting an environment variable called `LOADER_PATH` or `loader.path` in `loader.properties` (which is a comma-separated list of directories, archives, or directories within archives).
[[appendix.executable-jar.launching.manifest]]
== Launcher Manifest
You need to specify an appropriate `Launcher` as the `Main-Class` attribute of `META-INF/MANIFEST.MF`.
The actual class that you want to launch (that is, the class that contains a `main` method) should be specified in the `Start-Class` attribute.
The following example shows a typical `MANIFEST.MF` for an executable jar file:
[source,manifest]
----
Main-Class: org.springframework.boot.loader.launch.JarLauncher
Start-Class: com.mycompany.project.MyApplication
----
For a war file, it would be as follows:
[source,manifest]
----
Main-Class: org.springframework.boot.loader.launch.WarLauncher
Start-Class: com.mycompany.project.MyApplication
----
NOTE: You need not specify `Class-Path` entries in your manifest file.
The classpath is deduced from the nested jars.

View File

@@ -0,0 +1,149 @@
[[appendix.executable-jar.nested-jars]]
= Nested JARs
Java does not provide any standard way to load nested jar files (that is, jar files that are themselves contained within a jar).
This can be problematic if you need to distribute a self-contained application that can be run from the command line without unpacking.
To solve this problem, many developers use "`shaded`" jars.
A shaded jar packages all classes, from all jars, into a single "`uber jar`".
The problem with shaded jars is that it becomes hard to see which libraries are actually in your application.
It can also be problematic if the same filename is used (but with different content) in multiple jars.
Spring Boot takes a different approach and lets you actually nest jars directly.
[[appendix.executable-jar.nested-jars.jar-structure]]
== The Executable Jar File Structure
Spring Boot Loader-compatible jar files should be structured in the following way:
[source]
----
example.jar
|
+-META-INF
| +-MANIFEST.MF
+-org
| +-springframework
| +-boot
| +-loader
| +-<spring boot loader classes>
+-BOOT-INF
+-classes
| +-mycompany
| +-project
| +-YourClasses.class
+-lib
+-dependency1.jar
+-dependency2.jar
----
Application classes should be placed in a nested `BOOT-INF/classes` directory.
Dependencies should be placed in a nested `BOOT-INF/lib` directory.
[[appendix.executable-jar.nested-jars.war-structure]]
== The Executable War File Structure
Spring Boot Loader-compatible war files should be structured in the following way:
[source]
----
example.war
|
+-META-INF
| +-MANIFEST.MF
+-org
| +-springframework
| +-boot
| +-loader
| +-<spring boot loader classes>
+-WEB-INF
+-classes
| +-com
| +-mycompany
| +-project
| +-YourClasses.class
+-lib
| +-dependency1.jar
| +-dependency2.jar
+-lib-provided
+-servlet-api.jar
+-dependency3.jar
----
Dependencies should be placed in a nested `WEB-INF/lib` directory.
Any dependencies that are required when running embedded but are not required when deploying to a traditional web container should be placed in `WEB-INF/lib-provided`.
[[appendix.executable-jar.nested-jars.index-files]]
== Index Files
Spring Boot Loader-compatible jar and war archives can include additional index files under the `BOOT-INF/` directory.
A `classpath.idx` file can be provided for both jars and wars, and it provides the ordering that jars should be added to the classpath.
The `layers.idx` file can be used only for jars, and it allows a jar to be split into logical layers for Docker/OCI image creation.
Index files follow a YAML compatible syntax so that they can be easily parsed by third-party tools.
These files, however, are _not_ parsed internally as YAML and they must be written in exactly the formats described below in order to be used.
[[appendix.executable-jar.nested-jars.classpath-index]]
== Classpath Index
The classpath index file can be provided in `BOOT-INF/classpath.idx`.
Typically, it is generated automatically by Spring Boot's Maven and Gradle build plugins.
It provides a list of jar names (including the directory) in the order that they should be added to the classpath.
When generated by the build plugins, this classpath ordering matches that used by the build system for running and testing the application.
Each line must start with dash space (`"-&#183;"`) and names must be in double quotes.
For example, given the following jar:
[source]
----
example.jar
|
+-META-INF
| +-...
+-BOOT-INF
+-classes
| +...
+-lib
+-dependency1.jar
+-dependency2.jar
----
The index file would look like this:
[source]
----
- "BOOT-INF/lib/dependency2.jar"
- "BOOT-INF/lib/dependency1.jar"
----
[[appendix.executable-jar.nested-jars.layer-index]]
== Layer Index
The layers index file can be provided in `BOOT-INF/layers.idx`.
It provides a list of layers and the parts of the jar that should be contained within them.
Layers are written in the order that they should be added to the Docker/OCI image.
Layers names are written as quoted strings prefixed with dash space (`"-&#183;"`) and with a colon (`":"`) suffix.
Layer content is either a file or directory name written as a quoted string prefixed by space space dash space (`"&#183;&#183;-&#183;"`).
A directory name ends with `/`, a file name does not.
When a directory name is used it means that all files inside that directory are in the same layer.
A typical example of a layers index would be:
[source]
----
- "dependencies":
- "BOOT-INF/lib/dependency1.jar"
- "BOOT-INF/lib/dependency2.jar"
- "application":
- "BOOT-INF/classes/"
- "META-INF/"
----

View File

@@ -0,0 +1,82 @@
[[appendix.executable-jar.property-launcher]]
= PropertiesLauncher Features
`PropertiesLauncher` has a few special features that can be enabled with external properties (System properties, environment variables, manifest entries, or `loader.properties`).
The following table describes these properties:
|===
| Key | Purpose
| `loader.path`
| Comma-separated Classpath, such as `lib,$\{HOME}/app/lib`.
Earlier entries take precedence, like a regular `-classpath` on the `javac` command line.
| `loader.home`
| Used to resolve relative paths in `loader.path`.
For example, given `loader.path=lib`, then `${loader.home}/lib` is a classpath location (along with all jar files in that directory).
This property is also used to locate a `loader.properties` file, as in the following example `file:///opt/app` It defaults to `${user.dir}`.
| `loader.args`
| Default arguments for the main method (space separated).
| `loader.main`
| Name of main class to launch (for example, `com.app.Application`).
| `loader.config.name`
| Name of properties file (for example, `launcher`).
It defaults to `loader`.
| `loader.config.location`
| Path to properties file (for example, `classpath:loader.properties`).
It defaults to `loader.properties`.
| `loader.system`
| Boolean flag to indicate that all properties should be added to System properties.
It defaults to `false`.
|===
When specified as environment variables or manifest entries, the following names should be used:
|===
| Key | Manifest entry | Environment variable
| `loader.path`
| `Loader-Path`
| `LOADER_PATH`
| `loader.home`
| `Loader-Home`
| `LOADER_HOME`
| `loader.args`
| `Loader-Args`
| `LOADER_ARGS`
| `loader.main`
| `Start-Class`
| `LOADER_MAIN`
| `loader.config.location`
| `Loader-Config-Location`
| `LOADER_CONFIG_LOCATION`
| `loader.system`
| `Loader-System`
| `LOADER_SYSTEM`
|===
TIP: Build plugins automatically move the `Main-Class` attribute to `Start-Class` when the uber jar is built.
If you use that, specify the name of the class to launch by using the `Main-Class` attribute and leaving out `Start-Class`.
The following rules apply to working with `PropertiesLauncher`:
* `loader.properties` is searched for in `loader.home`, then in the root of the classpath, and then in `classpath:/BOOT-INF/classes`.
The first location where a file with that name exists is used.
* `loader.home` is the directory location of an additional properties file (overriding the default) only when `loader.config.location` is not specified.
* `loader.path` can contain directories (which are scanned recursively for jar and zip files), archive paths, a directory within an archive that is scanned for jar files (for example, `dependencies.jar!/lib`), or wildcard patterns (for the default JVM behavior).
Archive paths can be relative to `loader.home` or anywhere in the file system with a `jar:file:` prefix.
* `loader.path` (if empty) defaults to `BOOT-INF/lib` (meaning a local directory or a nested one if running from an archive).
Because of this, `PropertiesLauncher` behaves the same as `JarLauncher` when no additional configuration is provided.
* `loader.path` can not be used to configure the location of `loader.properties` (the classpath used to search for the latter is the JVM classpath when `PropertiesLauncher` is launched).
* Placeholder replacement is done from System and environment variables plus the properties file itself on all values before use.
* The search order for properties (where it makes sense to look in more than one place) is environment variables, system properties, `loader.properties`, the exploded archive manifest, and the archive manifest.

View File

@@ -0,0 +1,21 @@
[[appendix.executable-jar.restrictions]]
= Executable Jar Restrictions
You need to consider the following restrictions when working with a Spring Boot Loader packaged application:
[[appendix.executable-jar-zip-entry-compression]]
* Zip entry compression:
The `ZipEntry` for a nested jar must be saved by using the `ZipEntry.STORED` method.
This is required so that we can seek directly to individual content within the nested jar.
The content of the nested jar file itself can still be compressed, as can any other entry in the outer jar.
[[appendix.executable-jar-system-classloader]]
* System classLoader:
Launched applications should use `Thread.getContextClassLoader()` when loading classes (most libraries and frameworks do so by default).
Trying to load nested jar classes with `ClassLoader.getSystemClassLoader()` fails.
`java.util.Logging` always uses the system classloader.
For this reason, you should consider a different logging implementation.

View File

@@ -0,0 +1,14 @@
* Specifications
** xref:specification:configuration-metadata/index.adoc[]
*** xref:specification:configuration-metadata/format.adoc[]
*** xref:specification:configuration-metadata/manual-hints.adoc[]
*** xref:specification:configuration-metadata/annotation-processor.adoc[]
** xref:specification:executable-jar/index.adoc[]
*** xref:specification:executable-jar/nested-jars.adoc[]
*** xref:specification:executable-jar/jarfile-class.adoc[]
*** xref:specification:executable-jar/launching.adoc[]
*** xref:specification:executable-jar/property-launcher.adoc[]
*** xref:specification:executable-jar/restrictions.adoc[]
*** xref:specification:executable-jar/alternatives.adoc[]