|
17 | 17 | package org.springframework.boot.context.properties.migrator;
|
18 | 18 |
|
19 | 19 | import java.util.Collections;
|
| 20 | +import java.util.HashSet; |
20 | 21 | import java.util.LinkedHashMap;
|
21 | 22 | import java.util.List;
|
22 | 23 | import java.util.Map;
|
| 24 | +import java.util.Set; |
23 | 25 | import java.util.function.Predicate;
|
24 | 26 | import java.util.stream.Collectors;
|
25 | 27 |
|
@@ -86,14 +88,26 @@ private PropertySource<?> mapPropertiesWithReplacement(PropertiesMigrationReport
|
86 | 88 | if (renamed.isEmpty()) {
|
87 | 89 | return null;
|
88 | 90 | }
|
89 |
| - String target = "migrate-" + name; |
90 |
| - Map<String, OriginTrackedValue> content = new LinkedHashMap<>(); |
91 |
| - for (PropertyMigration candidate : renamed) { |
92 |
| - OriginTrackedValue value = OriginTrackedValue.of(candidate.getProperty().getValue(), |
93 |
| - candidate.getProperty().getOrigin()); |
94 |
| - content.put(candidate.getNewPropertyName(), value); |
| 91 | + NameTrackingPropertySource nameTrackingPropertySource = new NameTrackingPropertySource(); |
| 92 | + this.environment.getPropertySources().addFirst(nameTrackingPropertySource); |
| 93 | + try { |
| 94 | + String target = "migrate-" + name; |
| 95 | + Map<String, OriginTrackedValue> content = new LinkedHashMap<>(); |
| 96 | + for (PropertyMigration candidate : renamed) { |
| 97 | + String newPropertyName = candidate.getNewPropertyName(); |
| 98 | + Object value = candidate.getProperty().getValue(); |
| 99 | + if (nameTrackingPropertySource.isPlaceholderThatAccessesName(value, newPropertyName)) { |
| 100 | + continue; |
| 101 | + } |
| 102 | + OriginTrackedValue originTrackedValue = OriginTrackedValue.of(value, |
| 103 | + candidate.getProperty().getOrigin()); |
| 104 | + content.put(newPropertyName, originTrackedValue); |
| 105 | + } |
| 106 | + return new OriginTrackedMapPropertySource(target, content); |
| 107 | + } |
| 108 | + finally { |
| 109 | + this.environment.getPropertySources().remove(nameTrackingPropertySource.getName()); |
95 | 110 | }
|
96 |
| - return new OriginTrackedMapPropertySource(target, content); |
97 | 111 | }
|
98 | 112 |
|
99 | 113 | private boolean isMapType(ConfigurationMetadataProperty property) {
|
@@ -172,4 +186,33 @@ private String determinePropertySourceName(ConfigurationPropertySource source) {
|
172 | 186 | return source.getUnderlyingSource().toString();
|
173 | 187 | }
|
174 | 188 |
|
| 189 | + /** |
| 190 | + * {@link PropertySource} used to track accessed properties to protect against |
| 191 | + * circular references. |
| 192 | + */ |
| 193 | + private class NameTrackingPropertySource extends PropertySource<Object> { |
| 194 | + |
| 195 | + private final Set<String> accessedNames = new HashSet<>(); |
| 196 | + |
| 197 | + NameTrackingPropertySource() { |
| 198 | + super(NameTrackingPropertySource.class.getName()); |
| 199 | + } |
| 200 | + |
| 201 | + boolean isPlaceholderThatAccessesName(Object value, String name) { |
| 202 | + if (value instanceof String) { |
| 203 | + this.accessedNames.clear(); |
| 204 | + PropertiesMigrationReporter.this.environment.resolvePlaceholders((String) value); |
| 205 | + return this.accessedNames.contains(name); |
| 206 | + } |
| 207 | + return false; |
| 208 | + } |
| 209 | + |
| 210 | + @Override |
| 211 | + public Object getProperty(String name) { |
| 212 | + this.accessedNames.add(name); |
| 213 | + return null; |
| 214 | + } |
| 215 | + |
| 216 | + } |
| 217 | + |
175 | 218 | }
|
0 commit comments