From f24ba9935c1837c64e4f14ed6a59441c9420cf4c Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Tue, 21 Jan 2025 15:21:44 +0100 Subject: [PATCH] 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 --- .idea/codeStyles/Project.xml | 2 +- .../annotation-processor.adoc | 4 +- .../pages/configuration-metadata/format.adoc | 47 +++++++++- ...figurationMetadataAnnotationProcessor.java | 10 ++- .../metadata/ConfigurationMetadata.java | 45 +++++++++- .../metadata/ItemIgnore.java | 87 +++++++++++++++++++ .../metadata/JsonConverter.java | 24 ++++- .../metadata/JsonMarshaller.java | 24 ++++- ...ationMetadataAnnotationProcessorTests.java | 24 ++++- .../metadata/JsonMarshallerTests.java | 65 ++++++++++++-- .../simple/IgnoredProperties.java | 59 +++++++++++++ 11 files changed, 375 insertions(+), 16 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/ItemIgnore.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/IgnoredProperties.java diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 8c8b10622eb..a243a588d00 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -119,4 +119,4 @@ - \ No newline at end of file + diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/specification/pages/configuration-metadata/annotation-processor.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/specification/pages/configuration-metadata/annotation-processor.adoc index 04e9d53d3e7..941d73f9abb 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/specification/pages/configuration-metadata/annotation-processor.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/specification/pages/configuration-metadata/annotation-processor.adoc @@ -160,12 +160,14 @@ TIP: This has no effect on collections and maps, as those types are automaticall == 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. +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. 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 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. diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/specification/pages/configuration-metadata/format.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/specification/pages/configuration-metadata/format.adoc index db8964b1476..baf80ff5aee 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/specification/pages/configuration-metadata/format.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/specification/pages/configuration-metadata/format.adoc @@ -2,7 +2,7 @@ = 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: +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: [source,json] ---- @@ -63,7 +63,15 @@ They use a JSON format with items categorized under either "`groups`" or "`prope } ] } -]} + ... +],"ignored": { + "properties": [ + { + "name": "server.ignored" + } + ... + ] +}} ---- 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 ` 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. +The "`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. +Finally, "`ignored`" are items which have been deliberately ignored. +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]. + [[appendix.configuration-metadata.format.group]] @@ -292,6 +303,36 @@ The JSON object contained in the `providers` attribute of each `hint` element ca +[[appendix.configuration-metadata.format.ignored]] +== Ignored Attributes + +The `ignored` object can contain the attributes shown in the following table: + +[cols="1,1,4"] +|=== +| Name | Type | Purpose + +| `properties` +| IgnoredProperty[] +| 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. + +|=== + +The JSON object contained in the `properties` attribute of each `ignored` element can contain the attributes described in the following table: + +[cols="1,1,4"] +|=== +| Name | Type | Purpose + +| `name` +| String +| The full name of the property to ignore. +Names are in lower-case period-separated form (such as `spring.mvc.servlet.path`). +This attribute is mandatory. + +|=== + + [[appendix.configuration-metadata.format.repeated-items]] == Repeated Metadata Items diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessor.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessor.java index e44bd5e54f6..4e18cb46659 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessor.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,6 +48,7 @@ import javax.tools.Diagnostic.Kind; import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata; import org.springframework.boot.configurationprocessor.metadata.InvalidConfigurationMetadataException; import org.springframework.boot.configurationprocessor.metadata.ItemDeprecation; +import org.springframework.boot.configurationprocessor.metadata.ItemIgnore; import org.springframework.boot.configurationprocessor.metadata.ItemMetadata; /** @@ -372,6 +373,7 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor protected ConfigurationMetadata writeMetadata() throws Exception { ConfigurationMetadata metadata = this.metadataCollector.getMetadata(); metadata = mergeAdditionalMetadata(metadata); + removeIgnored(metadata); if (!metadata.getItems().isEmpty()) { this.metadataStore.writeMetadata(metadata); return metadata; @@ -379,6 +381,12 @@ public class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor return null; } + private void removeIgnored(ConfigurationMetadata metadata) { + for (ItemIgnore itemIgnore : metadata.getIgnored()) { + metadata.removeMetadata(itemIgnore.getType(), itemIgnore.getName()); + } + } + private ConfigurationMetadata mergeAdditionalMetadata(ConfigurationMetadata metadata) { try { ConfigurationMetadata merged = new ConfigurationMetadata(metadata); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/ConfigurationMetadata.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/ConfigurationMetadata.java index 3b8c1fd2785..d8085738bc9 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/ConfigurationMetadata.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/ConfigurationMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import org.springframework.boot.configurationprocessor.metadata.ItemMetadata.ItemType; import org.springframework.boot.configurationprocessor.support.ConventionUtils; /** @@ -29,6 +30,7 @@ import org.springframework.boot.configurationprocessor.support.ConventionUtils; * * @author Stephane Nicoll * @author Phillip Webb + * @author Moritz Halbritter * @since 1.2.0 * @see ItemMetadata */ @@ -38,14 +40,18 @@ public class ConfigurationMetadata { private final Map> hints; + private final Map> ignored; + public ConfigurationMetadata() { this.items = new LinkedHashMap<>(); this.hints = new LinkedHashMap<>(); + this.ignored = new LinkedHashMap<>(); } public ConfigurationMetadata(ConfigurationMetadata metadata) { this.items = new LinkedHashMap<>(metadata.items); this.hints = new LinkedHashMap<>(metadata.hints); + this.ignored = new LinkedHashMap<>(metadata.ignored); } /** @@ -73,6 +79,32 @@ public class ConfigurationMetadata { add(this.hints, itemHint.getName(), itemHint, false); } + /** + * Add item ignore. + * @param itemIgnore the item ignore to add + * @since 3.5.0 + */ + public void add(ItemIgnore itemIgnore) { + add(this.ignored, itemIgnore.getName(), itemIgnore, false); + } + + /** + * Remove item meta-data for the given item type and name. + * @param itemType the item type + * @param name the name + * @since 3.5.0 + */ + public void removeMetadata(ItemType itemType, String name) { + List metadata = this.items.get(name); + if (metadata == null) { + return; + } + metadata.removeIf((item) -> item.isOfItemType(itemType)); + if (metadata.isEmpty()) { + this.items.remove(name); + } + } + /** * Merge the content from another {@link ConfigurationMetadata}. * @param metadata the {@link ConfigurationMetadata} instance to merge @@ -84,6 +116,9 @@ public class ConfigurationMetadata { for (ItemHint itemHint : metadata.getHints()) { add(itemHint); } + for (ItemIgnore itemIgnore : metadata.getIgnored()) { + add(itemIgnore); + } } /** @@ -102,6 +137,14 @@ public class ConfigurationMetadata { return flattenValues(this.hints); } + /** + * Return ignore meta-data. + * @return the ignores + */ + public List getIgnored() { + return flattenValues(this.ignored); + } + protected void mergeItemMetadata(ItemMetadata metadata) { ItemMetadata matching = findMatchingItemMetadata(metadata); if (matching != null) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/ItemIgnore.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/ItemIgnore.java new file mode 100644 index 00000000000..f29d22c132b --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/ItemIgnore.java @@ -0,0 +1,87 @@ +/* + * Copyright 2012-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.configurationprocessor.metadata; + +import java.util.Objects; + +import org.springframework.boot.configurationprocessor.metadata.ItemMetadata.ItemType; + +/** + * Ignored item. + * + * @author Moritz Halbritter + * @since 3.5.0 + */ +public final class ItemIgnore implements Comparable { + + private final ItemType type; + + private final String name; + + private ItemIgnore(ItemType type, String name) { + if (name == null) { + throw new IllegalArgumentException("'name' must not be null"); + } + if (type == null) { + throw new IllegalArgumentException("'type' must not be null"); + } + this.type = type; + this.name = name; + } + + public String getName() { + return this.name; + } + + public ItemType getType() { + return this.type; + } + + @Override + public int compareTo(ItemIgnore other) { + return getName().compareTo(other.getName()); + } + + /** + * Create an ignore for a property with the given name. + * @param name the name + * @return the item ignore + */ + public static ItemIgnore forProperty(String name) { + return new ItemIgnore(ItemType.PROPERTY, name); + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + ItemIgnore that = (ItemIgnore) o; + return this.type == that.type && Objects.equals(this.name, that.name); + } + + @Override + public int hashCode() { + return Objects.hash(this.type, this.name); + } + + @Override + public String toString() { + return "ItemIgnore{" + "type=" + this.type + ", name='" + this.name + '\'' + '}'; + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonConverter.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonConverter.java index bd6239e19df..c33cf67f142 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonConverter.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ import org.springframework.boot.configurationprocessor.metadata.ItemMetadata.Ite * * @author Stephane Nicoll * @author Phillip Webb + * @author Moritz Halbritter */ class JsonConverter { @@ -59,6 +60,21 @@ class JsonConverter { return jsonArray; } + JSONObject toJsonObject(Collection ignored) throws Exception { + JSONObject result = new JSONObject(); + result.put("properties", ignoreToJsonArray( + ignored.stream().filter((itemIgnore) -> itemIgnore.getType() == ItemType.PROPERTY).toList())); + return result; + } + + private JSONArray ignoreToJsonArray(Collection ignored) throws Exception { + JSONArray result = new JSONArray(); + for (ItemIgnore itemIgnore : ignored) { + result.put(toJsonObject(itemIgnore)); + } + return result; + } + JSONObject toJsonObject(ItemMetadata item) throws Exception { JSONObject jsonObject = new JSONObject(); jsonObject.put("name", item.getName()); @@ -103,6 +119,12 @@ class JsonConverter { return jsonObject; } + private JSONObject toJsonObject(ItemIgnore ignore) throws Exception { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("name", ignore.getName()); + return jsonObject; + } + private JSONArray getItemHintValues(ItemHint hint) throws Exception { JSONArray values = new JSONArray(); for (ItemHint.ValueHint value : hint.getValues()) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonMarshaller.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonMarshaller.java index e7d6e84e8a2..06344157aeb 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonMarshaller.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonMarshaller.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ import java.util.Set; import java.util.TreeSet; import org.springframework.boot.configurationprocessor.json.JSONArray; +import org.springframework.boot.configurationprocessor.json.JSONException; import org.springframework.boot.configurationprocessor.json.JSONObject; import org.springframework.boot.configurationprocessor.metadata.ItemMetadata.ItemType; @@ -50,6 +51,7 @@ public class JsonMarshaller { object.put("groups", converter.toJsonArray(metadata, ItemType.GROUP)); object.put("properties", converter.toJsonArray(metadata, ItemType.PROPERTY)); object.put("hints", converter.toJsonArray(metadata.getHints())); + object.put("ignored", converter.toJsonObject(metadata.getIgnored())); outputStream.write(object.toString(2).getBytes(StandardCharsets.UTF_8)); } catch (Exception ex) { @@ -67,7 +69,7 @@ public class JsonMarshaller { ConfigurationMetadata metadata = new ConfigurationMetadata(); JSONObject object = new JSONObject(toString(inputStream)); JsonPath path = JsonPath.root(); - checkAllowedKeys(object, path, "groups", "properties", "hints"); + checkAllowedKeys(object, path, "groups", "properties", "hints", "ignored"); JSONArray groups = object.optJSONArray("groups"); if (groups != null) { for (int i = 0; i < groups.length(); i++) { @@ -88,9 +90,27 @@ public class JsonMarshaller { metadata.add(toItemHint((JSONObject) hints.get(i), path.resolve("hints").index(i))); } } + JSONObject ignored = object.optJSONObject("ignored"); + if (ignored != null) { + checkAllowedKeys(ignored, path.resolve("ignored"), "properties"); + addIgnoredProperties(metadata, ignored, path.resolve("ignored")); + } return metadata; } + private void addIgnoredProperties(ConfigurationMetadata metadata, JSONObject ignored, JsonPath path) + throws JSONException { + JSONArray properties = ignored.optJSONArray("properties"); + if (properties == null) { + return; + } + for (int i = 0; i < properties.length(); i++) { + JSONObject jsonObject = properties.getJSONObject(i); + checkAllowedKeys(jsonObject, path.resolve("properties").index(i), "name"); + metadata.add(ItemIgnore.forProperty(jsonObject.getString("name"))); + } + } + private ItemMetadata toItemMetadata(JSONObject object, JsonPath path, ItemType itemType) throws Exception { switch (itemType) { case GROUP -> checkAllowedKeys(object, path, "name", "type", "description", "sourceType", "sourceMethod"); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java index ac87c915d85..d659e13de75 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import java.time.temporal.ChronoUnit; import org.junit.jupiter.api.Test; import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata; +import org.springframework.boot.configurationprocessor.metadata.ItemIgnore; import org.springframework.boot.configurationprocessor.metadata.ItemMetadata; import org.springframework.boot.configurationprocessor.metadata.Metadata; import org.springframework.boot.configurationsample.deprecation.Dbcp2Configuration; @@ -38,6 +39,7 @@ import org.springframework.boot.configurationsample.simple.DescriptionProperties import org.springframework.boot.configurationsample.simple.HierarchicalProperties; import org.springframework.boot.configurationsample.simple.HierarchicalPropertiesGrandparent; import org.springframework.boot.configurationsample.simple.HierarchicalPropertiesParent; +import org.springframework.boot.configurationsample.simple.IgnoredProperties; import org.springframework.boot.configurationsample.simple.InnerClassWithPrivateConstructor; import org.springframework.boot.configurationsample.simple.NotAnnotated; import org.springframework.boot.configurationsample.simple.SimpleArrayProperties; @@ -570,4 +572,24 @@ class ConfigurationMetadataAnnotationProcessorTests extends AbstractMetadataGene .withDescription("last description in Javadoc")); } + @Test + void shouldIgnoreProperties() { + String additionalMetadata = """ + { + "ignored": { + "properties": [ + { + "name": "ignored.prop3" + } + ] + } + } + """; + ConfigurationMetadata metadata = compile(additionalMetadata, IgnoredProperties.class); + assertThat(metadata).has(Metadata.withProperty("ignored.prop1", String.class)); + assertThat(metadata).has(Metadata.withProperty("ignored.prop2", String.class)); + assertThat(metadata).doesNotHave(Metadata.withProperty("ignored.prop3", String.class)); + assertThat(metadata.getIgnored()).containsExactly(ItemIgnore.forProperty("ignored.prop3")); + } + } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/metadata/JsonMarshallerTests.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/metadata/JsonMarshallerTests.java index 00252fc252e..df7792cf073 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/metadata/JsonMarshallerTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/metadata/JsonMarshallerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ import static org.assertj.core.api.Assertions.assertThatException; * * @author Phillip Webb * @author Stephane Nicoll + * @author Moritz Halbritter */ class JsonMarshallerTests { @@ -174,14 +175,36 @@ class JsonMarshallerTests { "\"java.lang.Boolean\"", "\"com.example.bravo.aaa\"", "\"java.lang.Integer\"", "\"com.example.Bar"); } + @Test + void shouldReadIgnoredProperties() throws Exception { + String json = """ + { + "ignored": { + "properties": [ + { + "name": "prop1" + }, + { + "name": "prop2" + } + ] + } + } + """; + ConfigurationMetadata metadata = read(json); + assertThat(metadata.getIgnored()).containsExactly(ItemIgnore.forProperty("prop1"), + ItemIgnore.forProperty("prop2")); + } + @Test void shouldCheckRootFields() { String json = """ { - "groups": [], "properties": [], "hints": [], "dummy": [] + "groups": [], "properties": [], "hints": [], "ignored": {}, "dummy": [] }"""; assertThatException().isThrownBy(() -> read(json)) - .withMessage("Expected only keys [groups, hints, properties], but found additional keys [dummy]. Path: ."); + .withMessage( + "Expected only keys [groups, hints, ignored, properties], but found additional keys [dummy]. Path: ."); } @Test @@ -324,9 +347,41 @@ class JsonMarshallerTests { "Expected only keys [name, parameters], but found additional keys [dummy]. Path: .hints.[0].providers.[0]"); } - private void read(String json) throws Exception { + @Test + void shouldCheckIgnoreFields() { + String json = """ + { + "ignored": { + "properties": [], + "dummy": {} + } + } + """; + assertThatException().isThrownBy(() -> read(json)) + .withMessage("Expected only keys [properties], but found additional keys [dummy]. Path: .ignored"); + } + + @Test + void shouldCheckIgnorePropertiesFields() { + String json = """ + { + "ignored": { + "properties": [ + { + "name": "prop1", + "dummy": true + } + ] + } + } + """; + assertThatException().isThrownBy(() -> read(json)) + .withMessage("Expected only keys [name], but found additional keys [dummy]. Path: .ignored.properties.[0]"); + } + + private ConfigurationMetadata read(String json) throws Exception { JsonMarshaller marshaller = new JsonMarshaller(); - marshaller.read(new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8))); + return marshaller.read(new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8))); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/IgnoredProperties.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/IgnoredProperties.java new file mode 100644 index 00000000000..a68138c0396 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/IgnoredProperties.java @@ -0,0 +1,59 @@ +/* + * Copyright 2012-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.configurationsample.simple; + +import org.springframework.boot.configurationsample.ConfigurationProperties; + +/** + * Configuration properties where some of them are being ignored. + * + * @author Moritz Halbritter + */ +@ConfigurationProperties("ignored") +public class IgnoredProperties { + + private String prop1; + + private String prop2; + + private String prop3; + + public String getProp1() { + return this.prop1; + } + + public void setProp1(String prop1) { + this.prop1 = prop1; + } + + public String getProp2() { + return this.prop2; + } + + public void setProp2(String prop2) { + this.prop2 = prop2; + } + + public String getProp3() { + return this.prop3; + } + + public void setProp3(String prop3) { + this.prop3 = prop3; + } + +}