Browse Source

Merge branch '4.0.x'

Closes gh-49035
main
Andy Wilkinson 21 hours ago
parent
commit
8774d9286b
  1. 3
      buildSrc/src/main/java/org/springframework/boot/build/context/properties/CheckAdditionalSpringConfigurationMetadata.java
  2. 3
      buildSrc/src/main/java/org/springframework/boot/build/context/properties/CheckManualSpringConfigurationMetadata.java
  3. 54
      buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationPropertiesAnalyzer.java
  4. 41
      buildSrc/src/test/java/org/springframework/boot/build/context/properties/ConfigurationPropertiesAnalyzerTests.java
  5. 11
      module/spring-boot-jdbc/src/main/resources/META-INF/additional-spring-configuration-metadata.json

3
buildSrc/src/main/java/org/springframework/boot/build/context/properties/CheckAdditionalSpringConfigurationMetadata.java

@ -58,7 +58,8 @@ public abstract class CheckAdditionalSpringConfigurationMetadata extends SourceT @@ -58,7 +58,8 @@ public abstract class CheckAdditionalSpringConfigurationMetadata extends SourceT
void check() throws IOException {
ConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(getSource().getFiles());
Report report = new Report(this.projectDir);
analyzer.analyzeSort(report);
analyzer.analyzeOrder(report);
analyzer.analyzeDuplicates(report);
analyzer.analyzeDeprecationSince(report);
File reportFile = getReportLocation().get().getAsFile();
report.write(reportFile);

3
buildSrc/src/main/java/org/springframework/boot/build/context/properties/CheckManualSpringConfigurationMetadata.java

@ -64,7 +64,8 @@ public abstract class CheckManualSpringConfigurationMetadata extends DefaultTask @@ -64,7 +64,8 @@ public abstract class CheckManualSpringConfigurationMetadata extends DefaultTask
ConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(
List.of(getMetadataLocation().get()));
Report report = new Report(this.projectDir);
analyzer.analyzeSort(report);
analyzer.analyzeOrder(report);
analyzer.analyzeDuplicates(report);
analyzer.analyzePropertyDescription(report, getExclusions().get());
analyzer.analyzeDeprecationSince(report);
File reportFile = getReportLocation().get().getAsFile();

54
buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationPropertiesAnalyzer.java

@ -25,9 +25,11 @@ import java.nio.file.StandardOpenOption; @@ -25,9 +25,11 @@ import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import tools.jackson.core.StreamReadFeature;
@ -40,15 +42,18 @@ import org.springframework.util.function.SingletonSupplier; @@ -40,15 +42,18 @@ import org.springframework.util.function.SingletonSupplier;
/**
* Check configuration metadata for inconsistencies. The available checks are:
* <ul>
* <li>Metadata element should be sorted alphabetically: {@link #analyzeSort(Report)}</li>
* <li>Property must have a description:
* {@link #analyzePropertyDescription(Report, List)}</li>
* <li>Metadata elements {@link #analyzeOrder(Report) must be sorted alphabetically}</li>
* <li>Metadata elements {@link #analyzeDuplicates(Report) must not be duplicates}</li>
* <li>Properties {@link #analyzePropertyDescription(Report, List) must have a
* description}</li>
* </ul>
*
* @author Stephane Nicoll
*/
class ConfigurationPropertiesAnalyzer {
private static final List<String> ELEMENT_TYPES = List.of("groups", "properties", "hints");
private final Collection<File> sources;
private final SingletonSupplier<JsonMapper> jsonMapperSupplier;
@ -62,23 +67,23 @@ class ConfigurationPropertiesAnalyzer { @@ -62,23 +67,23 @@ class ConfigurationPropertiesAnalyzer {
.of(() -> JsonMapper.builder().enable(StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION).build());
}
void analyzeSort(Report report) {
void analyzeOrder(Report report) {
for (File source : this.sources) {
report.registerAnalysis(source, analyzeSort(source));
report.registerAnalysis(source, analyzeOrder(source));
}
}
private Analysis analyzeSort(File source) {
private Analysis analyzeOrder(File source) {
Map<String, Object> json = readJsonContent(source);
Analysis analysis = new Analysis("Metadata element order:");
analyzeMetadataElementsSort("groups", json, analysis);
analyzeMetadataElementsSort("properties", json, analysis);
analyzeMetadataElementsSort("hints", json, analysis);
for (String elementType : ELEMENT_TYPES) {
analyzeMetadataElementOrder(elementType, json, analysis);
}
return analysis;
}
@SuppressWarnings("unchecked")
private void analyzeMetadataElementsSort(String key, Map<String, Object> json, Analysis analysis) {
private void analyzeMetadataElementOrder(String key, Map<String, Object> json, Analysis analysis) {
List<Map<String, Object>> groups = (List<Map<String, Object>>) json.getOrDefault(key, Collections.emptyList());
List<String> names = groups.stream().map((group) -> (String) group.get("name")).toList();
List<String> sortedNames = names.stream().sorted().toList();
@ -92,6 +97,35 @@ class ConfigurationPropertiesAnalyzer { @@ -92,6 +97,35 @@ class ConfigurationPropertiesAnalyzer {
}
}
void analyzeDuplicates(Report report) {
for (File source : this.sources) {
report.registerAnalysis(source, analyzeDuplicates(source));
}
}
private Analysis analyzeDuplicates(File source) {
Map<String, Object> json = readJsonContent(source);
Analysis analysis = new Analysis("Metadata element duplicates:");
for (String elementType : ELEMENT_TYPES) {
analyzeMetadataElementDuplicates(elementType, json, analysis);
}
return analysis;
}
@SuppressWarnings("unchecked")
private void analyzeMetadataElementDuplicates(String key, Map<String, Object> json, Analysis analysis) {
List<Map<String, Object>> elements = (List<Map<String, Object>>) json.getOrDefault(key,
Collections.emptyList());
List<String> names = elements.stream().map((group) -> (String) group.get("name")).toList();
Set<String> uniqueNames = new HashSet<>();
for (int i = 0; i < names.size(); i++) {
String name = names.get(i);
if (!uniqueNames.add(name)) {
analysis.addItem("Duplicate name '" + name + "' at $." + key + "[" + i + "]");
}
}
}
void analyzePropertyDescription(Report report, List<String> exclusions) {
for (File source : this.sources) {
report.registerAnalysis(source, analyzePropertyDescription(source, exclusions));

41
buildSrc/src/test/java/org/springframework/boot/build/context/properties/ConfigurationPropertiesAnalyzerTests.java

@ -46,7 +46,7 @@ class ConfigurationPropertiesAnalyzerTests { @@ -46,7 +46,7 @@ class ConfigurationPropertiesAnalyzerTests {
}
@Test
void analyzeSortWithAlphabeticalOrder(@TempDir File tempDir) throws IOException {
void analyzeOrderWithAlphabeticalOrder(@TempDir File tempDir) throws IOException {
File metadata = new File(tempDir, "metadata.json");
Files.writeString(metadata.toPath(), """
{ "properties": [
@ -55,14 +55,14 @@ class ConfigurationPropertiesAnalyzerTests { @@ -55,14 +55,14 @@ class ConfigurationPropertiesAnalyzerTests {
}""");
Report report = new Report(tempDir);
ConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(List.of(metadata));
analyzer.analyzeSort(report);
analyzer.analyzeOrder(report);
assertThat(report.hasProblems()).isFalse();
assertThat(report.getAnalyses(metadata)).singleElement()
.satisfies(((analysis) -> assertThat(analysis.getItems()).isEmpty()));
}
@Test
void analyzeSortWithViolations(@TempDir File tempDir) throws IOException {
void analyzeOrderWithViolations(@TempDir File tempDir) throws IOException {
File metadata = new File(tempDir, "metadata.json");
Files.writeString(metadata.toPath(), """
{ "properties": [
@ -71,7 +71,7 @@ class ConfigurationPropertiesAnalyzerTests { @@ -71,7 +71,7 @@ class ConfigurationPropertiesAnalyzerTests {
}""");
Report report = new Report(tempDir);
ConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(List.of(metadata));
analyzer.analyzeSort(report);
analyzer.analyzeOrder(report);
assertThat(report.hasProblems()).isTrue();
assertThat(report.getAnalyses(metadata)).singleElement()
.satisfies((analysis) -> assertThat(analysis.getItems()).containsExactly(
@ -79,6 +79,39 @@ class ConfigurationPropertiesAnalyzerTests { @@ -79,6 +79,39 @@ class ConfigurationPropertiesAnalyzerTests {
"Wrong order at $.properties[1].name - expected 'def' but found 'abc'"));
}
@Test
void analyzeDuplicatesWithNoDuplicates(@TempDir File tempDir) throws IOException {
File metadata = new File(tempDir, "metadata.json");
Files.writeString(metadata.toPath(), """
{ "properties": [
{ "name": "abc"}, {"name": "def"}, {"name": "xyz"}
]
}""");
Report report = new Report(tempDir);
ConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(List.of(metadata));
analyzer.analyzeOrder(report);
assertThat(report.hasProblems()).isFalse();
assertThat(report.getAnalyses(metadata)).singleElement()
.satisfies(((analysis) -> assertThat(analysis.getItems()).isEmpty()));
}
@Test
void analyzeDuplicatesWithDuplicate(@TempDir File tempDir) throws IOException {
File metadata = new File(tempDir, "metadata.json");
Files.writeString(metadata.toPath(), """
{ "properties": [
{ "name": "abc"}, {"name": "abc"}, {"name": "def"}
]
}""");
Report report = new Report(tempDir);
ConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(List.of(metadata));
analyzer.analyzeDuplicates(report);
assertThat(report.hasProblems()).isTrue();
assertThat(report.getAnalyses(metadata)).singleElement()
.satisfies((analysis) -> assertThat(analysis.getItems())
.containsExactly("Duplicate name 'abc' at $.properties[1]"));
}
@Test
void analyzePropertyDescription(@TempDir File tempDir) throws IOException {
File metadata = new File(tempDir, "metadata.json");

11
module/spring-boot-jdbc/src/main/resources/META-INF/additional-spring-configuration-metadata.json

@ -151,17 +151,6 @@ @@ -151,17 +151,6 @@
}
]
},
{
"name": "spring.datasource.xa.data-source-class-name",
"providers": [
{
"name": "class-reference",
"parameters": {
"target": "javax.sql.XADataSource"
}
}
]
},
{
"name": "spring.datasource.xa.data-source-class-name",
"providers": [

Loading…
Cancel
Save