Skip to content

Commit f24ba99

Browse files
committed
Add ability to ignore configuration properties
Properties which should be ignored can be specified in the additional-spring-configuration-metadata.json file. The ignored properties section is copied into the final spring-configuration-metadata.json file, and the ignored properties are removed from the properties element in the final file. Closes gh-2421
1 parent 08e9c16 commit f24ba99

File tree

11 files changed

+375
-16
lines changed

11 files changed

+375
-16
lines changed

.idea/codeStyles/Project.xml

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

spring-boot-project/spring-boot-docs/src/docs/antora/modules/specification/pages/configuration-metadata/annotation-processor.adoc

+3-1
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,14 @@ TIP: This has no effect on collections and maps, as those types are automaticall
160160
== Adding Additional Metadata
161161

162162
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.
163-
You may also need to tune some attributes of an existing key.
163+
You may also need to tune some attributes of an existing key or to ignore the key altogether.
164164
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.
165165

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

169169
The format of the `additional-spring-configuration-metadata.json` file is exactly the same as the regular `spring-configuration-metadata.json`.
170+
The items contained in the "`ignored.properties`" section are removed from the "`properties`" section of the generated `spring-configuration-metadata.json` file.
171+
170172
The additional properties file is optional.
171173
If you do not have any additional properties, do not add the file.

spring-boot-project/spring-boot-docs/src/docs/antora/modules/specification/pages/configuration-metadata/format.adoc

+44-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
= Metadata Format
33

44
Configuration metadata files are located inside jars under `META-INF/spring-configuration-metadata.json`.
5-
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:
5+
They use a JSON format with items categorized under either "`groups`" or "`properties`", additional values hints categorized under "hints", and ignored items under "`ignored`" as shown in the following example:
66

77
[source,json]
88
----
@@ -63,7 +63,15 @@ They use a JSON format with items categorized under either "`groups`" or "`prope
6363
}
6464
]
6565
}
66-
]}
66+
...
67+
],"ignored": {
68+
"properties": [
69+
{
70+
"name": "server.ignored"
71+
}
72+
...
73+
]
74+
}}
6775
----
6876

6977
Each "`property`" is a configuration item that the user specifies with a given value.
@@ -82,9 +90,12 @@ For example, the `server.port` and `server.address` properties are part of the `
8290
NOTE: It is not required that every "`property`" has a "`group`".
8391
Some properties might exist in their own right.
8492

85-
Finally, "`hints`" are additional information used to assist the user in configuring a given property.
93+
The "`hints`" are additional information used to assist the user in configuring a given property.
8694
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.
8795

96+
Finally, "`ignored`" are items which have been deliberately ignored.
97+
The content of this section usually comes from the xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.adding-additional-metadata[additional metadata].
98+
8899

89100

90101
[[appendix.configuration-metadata.format.group]]
@@ -292,6 +303,36 @@ The JSON object contained in the `providers` attribute of each `hint` element ca
292303

293304

294305

306+
[[appendix.configuration-metadata.format.ignored]]
307+
== Ignored Attributes
308+
309+
The `ignored` object can contain the attributes shown in the following table:
310+
311+
[cols="1,1,4"]
312+
|===
313+
| Name | Type | Purpose
314+
315+
| `properties`
316+
| IgnoredProperty[]
317+
| A list of ignored properties as defined by the IgnoredProperty object (described in the next table). Each entry defines the name of the ignored property.
318+
319+
|===
320+
321+
The JSON object contained in the `properties` attribute of each `ignored` element can contain the attributes described in the following table:
322+
323+
[cols="1,1,4"]
324+
|===
325+
| Name | Type | Purpose
326+
327+
| `name`
328+
| String
329+
| The full name of the property to ignore.
330+
Names are in lower-case period-separated form (such as `spring.mvc.servlet.path`).
331+
This attribute is mandatory.
332+
333+
|===
334+
335+
295336
[[appendix.configuration-metadata.format.repeated-items]]
296337
== Repeated Metadata Items
297338

spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessor.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -48,6 +48,7 @@
4848
import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;
4949
import org.springframework.boot.configurationprocessor.metadata.InvalidConfigurationMetadataException;
5050
import org.springframework.boot.configurationprocessor.metadata.ItemDeprecation;
51+
import org.springframework.boot.configurationprocessor.metadata.ItemIgnore;
5152
import org.springframework.boot.configurationprocessor.metadata.ItemMetadata;
5253

5354
/**
@@ -372,13 +373,20 @@ private String getPrefix(AnnotationMirror annotation) {
372373
protected ConfigurationMetadata writeMetadata() throws Exception {
373374
ConfigurationMetadata metadata = this.metadataCollector.getMetadata();
374375
metadata = mergeAdditionalMetadata(metadata);
376+
removeIgnored(metadata);
375377
if (!metadata.getItems().isEmpty()) {
376378
this.metadataStore.writeMetadata(metadata);
377379
return metadata;
378380
}
379381
return null;
380382
}
381383

384+
private void removeIgnored(ConfigurationMetadata metadata) {
385+
for (ItemIgnore itemIgnore : metadata.getIgnored()) {
386+
metadata.removeMetadata(itemIgnore.getType(), itemIgnore.getName());
387+
}
388+
}
389+
382390
private ConfigurationMetadata mergeAdditionalMetadata(ConfigurationMetadata metadata) {
383391
try {
384392
ConfigurationMetadata merged = new ConfigurationMetadata(metadata);

spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/ConfigurationMetadata.java

+44-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,13 +22,15 @@
2222
import java.util.List;
2323
import java.util.Map;
2424

25+
import org.springframework.boot.configurationprocessor.metadata.ItemMetadata.ItemType;
2526
import org.springframework.boot.configurationprocessor.support.ConventionUtils;
2627

2728
/**
2829
* Configuration meta-data.
2930
*
3031
* @author Stephane Nicoll
3132
* @author Phillip Webb
33+
* @author Moritz Halbritter
3234
* @since 1.2.0
3335
* @see ItemMetadata
3436
*/
@@ -38,14 +40,18 @@ public class ConfigurationMetadata {
3840

3941
private final Map<String, List<ItemHint>> hints;
4042

43+
private final Map<String, List<ItemIgnore>> ignored;
44+
4145
public ConfigurationMetadata() {
4246
this.items = new LinkedHashMap<>();
4347
this.hints = new LinkedHashMap<>();
48+
this.ignored = new LinkedHashMap<>();
4449
}
4550

4651
public ConfigurationMetadata(ConfigurationMetadata metadata) {
4752
this.items = new LinkedHashMap<>(metadata.items);
4853
this.hints = new LinkedHashMap<>(metadata.hints);
54+
this.ignored = new LinkedHashMap<>(metadata.ignored);
4955
}
5056

5157
/**
@@ -73,6 +79,32 @@ public void add(ItemHint itemHint) {
7379
add(this.hints, itemHint.getName(), itemHint, false);
7480
}
7581

82+
/**
83+
* Add item ignore.
84+
* @param itemIgnore the item ignore to add
85+
* @since 3.5.0
86+
*/
87+
public void add(ItemIgnore itemIgnore) {
88+
add(this.ignored, itemIgnore.getName(), itemIgnore, false);
89+
}
90+
91+
/**
92+
* Remove item meta-data for the given item type and name.
93+
* @param itemType the item type
94+
* @param name the name
95+
* @since 3.5.0
96+
*/
97+
public void removeMetadata(ItemType itemType, String name) {
98+
List<ItemMetadata> metadata = this.items.get(name);
99+
if (metadata == null) {
100+
return;
101+
}
102+
metadata.removeIf((item) -> item.isOfItemType(itemType));
103+
if (metadata.isEmpty()) {
104+
this.items.remove(name);
105+
}
106+
}
107+
76108
/**
77109
* Merge the content from another {@link ConfigurationMetadata}.
78110
* @param metadata the {@link ConfigurationMetadata} instance to merge
@@ -84,6 +116,9 @@ public void merge(ConfigurationMetadata metadata) {
84116
for (ItemHint itemHint : metadata.getHints()) {
85117
add(itemHint);
86118
}
119+
for (ItemIgnore itemIgnore : metadata.getIgnored()) {
120+
add(itemIgnore);
121+
}
87122
}
88123

89124
/**
@@ -102,6 +137,14 @@ public List<ItemHint> getHints() {
102137
return flattenValues(this.hints);
103138
}
104139

140+
/**
141+
* Return ignore meta-data.
142+
* @return the ignores
143+
*/
144+
public List<ItemIgnore> getIgnored() {
145+
return flattenValues(this.ignored);
146+
}
147+
105148
protected void mergeItemMetadata(ItemMetadata metadata) {
106149
ItemMetadata matching = findMatchingItemMetadata(metadata);
107150
if (matching != null) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright 2012-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.configurationprocessor.metadata;
18+
19+
import java.util.Objects;
20+
21+
import org.springframework.boot.configurationprocessor.metadata.ItemMetadata.ItemType;
22+
23+
/**
24+
* Ignored item.
25+
*
26+
* @author Moritz Halbritter
27+
* @since 3.5.0
28+
*/
29+
public final class ItemIgnore implements Comparable<ItemIgnore> {
30+
31+
private final ItemType type;
32+
33+
private final String name;
34+
35+
private ItemIgnore(ItemType type, String name) {
36+
if (name == null) {
37+
throw new IllegalArgumentException("'name' must not be null");
38+
}
39+
if (type == null) {
40+
throw new IllegalArgumentException("'type' must not be null");
41+
}
42+
this.type = type;
43+
this.name = name;
44+
}
45+
46+
public String getName() {
47+
return this.name;
48+
}
49+
50+
public ItemType getType() {
51+
return this.type;
52+
}
53+
54+
@Override
55+
public int compareTo(ItemIgnore other) {
56+
return getName().compareTo(other.getName());
57+
}
58+
59+
/**
60+
* Create an ignore for a property with the given name.
61+
* @param name the name
62+
* @return the item ignore
63+
*/
64+
public static ItemIgnore forProperty(String name) {
65+
return new ItemIgnore(ItemType.PROPERTY, name);
66+
}
67+
68+
@Override
69+
public boolean equals(Object o) {
70+
if (o == null || getClass() != o.getClass()) {
71+
return false;
72+
}
73+
ItemIgnore that = (ItemIgnore) o;
74+
return this.type == that.type && Objects.equals(this.name, that.name);
75+
}
76+
77+
@Override
78+
public int hashCode() {
79+
return Objects.hash(this.type, this.name);
80+
}
81+
82+
@Override
83+
public String toString() {
84+
return "ItemIgnore{" + "type=" + this.type + ", name='" + this.name + '\'' + '}';
85+
}
86+
87+
}

spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonConverter.java

+23-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2024 the original author or authors.
2+
* Copyright 2012-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
3131
*
3232
* @author Stephane Nicoll
3333
* @author Phillip Webb
34+
* @author Moritz Halbritter
3435
*/
3536
class JsonConverter {
3637

@@ -59,6 +60,21 @@ JSONArray toJsonArray(Collection<ItemHint> hints) throws Exception {
5960
return jsonArray;
6061
}
6162

63+
JSONObject toJsonObject(Collection<ItemIgnore> ignored) throws Exception {
64+
JSONObject result = new JSONObject();
65+
result.put("properties", ignoreToJsonArray(
66+
ignored.stream().filter((itemIgnore) -> itemIgnore.getType() == ItemType.PROPERTY).toList()));
67+
return result;
68+
}
69+
70+
private JSONArray ignoreToJsonArray(Collection<ItemIgnore> ignored) throws Exception {
71+
JSONArray result = new JSONArray();
72+
for (ItemIgnore itemIgnore : ignored) {
73+
result.put(toJsonObject(itemIgnore));
74+
}
75+
return result;
76+
}
77+
6278
JSONObject toJsonObject(ItemMetadata item) throws Exception {
6379
JSONObject jsonObject = new JSONObject();
6480
jsonObject.put("name", item.getName());
@@ -103,6 +119,12 @@ private JSONObject toJsonObject(ItemHint hint) throws Exception {
103119
return jsonObject;
104120
}
105121

122+
private JSONObject toJsonObject(ItemIgnore ignore) throws Exception {
123+
JSONObject jsonObject = new JSONObject();
124+
jsonObject.put("name", ignore.getName());
125+
return jsonObject;
126+
}
127+
106128
private JSONArray getItemHintValues(ItemHint hint) throws Exception {
107129
JSONArray values = new JSONArray();
108130
for (ItemHint.ValueHint value : hint.getValues()) {

0 commit comments

Comments
 (0)