Merge branch '3.1.x'

This commit is contained in:
Phillip Webb 2023-06-16 16:17:59 -07:00
commit 8afbff3f28
2 changed files with 60 additions and 9 deletions

View File

@ -17,9 +17,11 @@
package org.springframework.boot.context.properties.migrator; package org.springframework.boot.context.properties.migrator;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -86,15 +88,27 @@ class PropertiesMigrationReporter {
if (renamed.isEmpty()) { if (renamed.isEmpty()) {
return null; return null;
} }
NameTrackingPropertySource nameTrackingPropertySource = new NameTrackingPropertySource();
this.environment.getPropertySources().addFirst(nameTrackingPropertySource);
try {
String target = "migrate-" + name; String target = "migrate-" + name;
Map<String, OriginTrackedValue> content = new LinkedHashMap<>(); Map<String, OriginTrackedValue> content = new LinkedHashMap<>();
for (PropertyMigration candidate : renamed) { for (PropertyMigration candidate : renamed) {
OriginTrackedValue value = OriginTrackedValue.of(candidate.getProperty().getValue(), String newPropertyName = candidate.getNewPropertyName();
Object value = candidate.getProperty().getValue();
if (nameTrackingPropertySource.isPlaceholderThatAccessesName(value, newPropertyName)) {
continue;
}
OriginTrackedValue originTrackedValue = OriginTrackedValue.of(value,
candidate.getProperty().getOrigin()); candidate.getProperty().getOrigin());
content.put(candidate.getNewPropertyName(), value); content.put(newPropertyName, originTrackedValue);
} }
return new OriginTrackedMapPropertySource(target, content); return new OriginTrackedMapPropertySource(target, content);
} }
finally {
this.environment.getPropertySources().remove(nameTrackingPropertySource.getName());
}
}
private boolean isMapType(ConfigurationMetadataProperty property) { private boolean isMapType(ConfigurationMetadataProperty property) {
String type = property.getType(); String type = property.getType();
@ -172,4 +186,33 @@ class PropertiesMigrationReporter {
return source.getUnderlyingSource().toString(); return source.getUnderlyingSource().toString();
} }
/**
* {@link PropertySource} used to track accessed properties to protect against
* circular references.
*/
private class NameTrackingPropertySource extends PropertySource<Object> {
private final Set<String> accessedNames = new HashSet<>();
NameTrackingPropertySource() {
super(NameTrackingPropertySource.class.getName());
}
boolean isPlaceholderThatAccessesName(Object value, String name) {
if (value instanceof String) {
this.accessedNames.clear();
PropertiesMigrationReporter.this.environment.resolvePlaceholders((String) value);
return this.accessedNames.contains(name);
}
return false;
}
@Override
public Object getProperty(String name) {
this.accessedNames.add(name);
return null;
}
}
} }

View File

@ -162,7 +162,7 @@ class PropertiesMigrationReporterTests {
} }
@Test @Test
void mapPropertiesDeprecatedNoReplacement() throws IOException { void mapPropertiesDeprecatedNoReplacement() {
this.environment.getPropertySources() this.environment.getPropertySources()
.addFirst( .addFirst(
new MapPropertySource("first", Collections.singletonMap("custom.map-no-replacement.key", "value"))); new MapPropertySource("first", Collections.singletonMap("custom.map-no-replacement.key", "value")));
@ -173,7 +173,7 @@ class PropertiesMigrationReporterTests {
} }
@Test @Test
void mapPropertiesDeprecatedWithReplacement() throws IOException { void mapPropertiesDeprecatedWithReplacement() {
this.environment.getPropertySources() this.environment.getPropertySources()
.addFirst(new MapPropertySource("first", .addFirst(new MapPropertySource("first",
Collections.singletonMap("custom.map-with-replacement.key", "value"))); Collections.singletonMap("custom.map-with-replacement.key", "value")));
@ -205,6 +205,14 @@ class PropertiesMigrationReporterTests {
.contains("Replacement: custom.the-map-replacement.key"); .contains("Replacement: custom.the-map-replacement.key");
} }
@Test // gh-35919
void directCircularReference() {
this.environment.getPropertySources()
.addFirst(new MapPropertySource("backcompat", Collections.singletonMap("wrong.two", "${test.two}")));
createAnalyzer(loadRepository("metadata/sample-metadata.json")).getReport();
assertThat(this.environment.getProperty("test.two")).isNull();
}
private List<String> mapToNames(PropertySources sources) { private List<String> mapToNames(PropertySources sources) {
List<String> names = new ArrayList<>(); List<String> names = new ArrayList<>();
for (PropertySource<?> source : sources) { for (PropertySource<?> source : sources) {