Skip to content

Commit 5fbfdbc

Browse files
committed
Merge branch '6.2.x'
2 parents 4f38c5b + 5a2cbc1 commit 5fbfdbc

File tree

1 file changed

+96
-70
lines changed

1 file changed

+96
-70
lines changed

spring-core/src/test/java/org/springframework/core/env/PropertySourcesPropertyResolverTests.java

+96-70
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-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.
@@ -21,6 +21,7 @@
2121
import java.util.Properties;
2222

2323
import org.junit.jupiter.api.BeforeEach;
24+
import org.junit.jupiter.api.Nested;
2425
import org.junit.jupiter.api.Test;
2526

2627
import org.springframework.core.convert.ConverterNotFoundException;
@@ -38,18 +39,15 @@
3839
*/
3940
class PropertySourcesPropertyResolverTests {
4041

41-
private Properties testProperties;
42+
private final Properties testProperties = new Properties();
4243

43-
private MutablePropertySources propertySources;
44+
private final MutablePropertySources propertySources = new MutablePropertySources();
4445

45-
private PropertySourcesPropertyResolver propertyResolver;
46+
private final PropertySourcesPropertyResolver propertyResolver = new PropertySourcesPropertyResolver(propertySources);
4647

4748

4849
@BeforeEach
4950
void setUp() {
50-
propertySources = new MutablePropertySources();
51-
propertyResolver = new PropertySourcesPropertyResolver(propertySources);
52-
testProperties = new Properties();
5351
propertySources.addFirst(new PropertiesPropertySource("testProperties", testProperties));
5452
}
5553

@@ -77,14 +75,12 @@ void getProperty_withDefaultValue() {
7775

7876
@Test
7977
void getProperty_propertySourceSearchOrderIsFIFO() {
80-
MutablePropertySources sources = new MutablePropertySources();
81-
PropertyResolver resolver = new PropertySourcesPropertyResolver(sources);
82-
sources.addFirst(new MockPropertySource("ps1").withProperty("pName", "ps1Value"));
83-
assertThat(resolver.getProperty("pName")).isEqualTo("ps1Value");
84-
sources.addFirst(new MockPropertySource("ps2").withProperty("pName", "ps2Value"));
85-
assertThat(resolver.getProperty("pName")).isEqualTo("ps2Value");
86-
sources.addFirst(new MockPropertySource("ps3").withProperty("pName", "ps3Value"));
87-
assertThat(resolver.getProperty("pName")).isEqualTo("ps3Value");
78+
propertySources.addFirst(new MockPropertySource("ps1").withProperty("pName", "ps1Value"));
79+
assertThat(propertyResolver.getProperty("pName")).isEqualTo("ps1Value");
80+
propertySources.addFirst(new MockPropertySource("ps2").withProperty("pName", "ps2Value"));
81+
assertThat(propertyResolver.getProperty("pName")).isEqualTo("ps2Value");
82+
propertySources.addFirst(new MockPropertySource("ps3").withProperty("pName", "ps3Value"));
83+
assertThat(propertyResolver.getProperty("pName")).isEqualTo("ps3Value");
8884
}
8985

9086
@Test
@@ -115,8 +111,8 @@ void getProperty_withNonConvertibleTargetType() {
115111

116112
class TestType { }
117113

118-
assertThatExceptionOfType(ConverterNotFoundException.class).isThrownBy(() ->
119-
propertyResolver.getProperty("foo", TestType.class));
114+
assertThatExceptionOfType(ConverterNotFoundException.class)
115+
.isThrownBy(() -> propertyResolver.getProperty("foo", TestType.class));
120116
}
121117

122118
@Test
@@ -127,7 +123,6 @@ void getProperty_doesNotCache_replaceExistingKeyPostConstruction() {
127123

128124
HashMap<String, Object> map = new HashMap<>();
129125
map.put(key, value1); // before construction
130-
MutablePropertySources propertySources = new MutablePropertySources();
131126
propertySources.addFirst(new MapPropertySource("testProperties", map));
132127
PropertyResolver propertyResolver = new PropertySourcesPropertyResolver(propertySources);
133128
assertThat(propertyResolver.getProperty(key)).isEqualTo(value1);
@@ -138,7 +133,6 @@ void getProperty_doesNotCache_replaceExistingKeyPostConstruction() {
138133
@Test
139134
void getProperty_doesNotCache_addNewKeyPostConstruction() {
140135
HashMap<String, Object> map = new HashMap<>();
141-
MutablePropertySources propertySources = new MutablePropertySources();
142136
propertySources.addFirst(new MapPropertySource("testProperties", map));
143137
PropertyResolver propertyResolver = new PropertySourcesPropertyResolver(propertySources);
144138
assertThat(propertyResolver.getProperty("foo")).isNull();
@@ -148,10 +142,9 @@ void getProperty_doesNotCache_addNewKeyPostConstruction() {
148142

149143
@Test
150144
void getPropertySources_replacePropertySource() {
151-
propertySources = new MutablePropertySources();
152-
propertyResolver = new PropertySourcesPropertyResolver(propertySources);
153145
propertySources.addLast(new MockPropertySource("local").withProperty("foo", "localValue"));
154146
propertySources.addLast(new MockPropertySource("system").withProperty("foo", "systemValue"));
147+
assertThat(propertySources).hasSize(3);
155148

156149
// 'local' was added first so has precedence
157150
assertThat(propertyResolver.getProperty("foo")).isEqualTo("localValue");
@@ -162,89 +155,73 @@ void getPropertySources_replacePropertySource() {
162155
// 'system' now has precedence
163156
assertThat(propertyResolver.getProperty("foo")).isEqualTo("newValue");
164157

165-
assertThat(propertySources).hasSize(2);
158+
assertThat(propertySources).hasSize(3);
166159
}
167160

168161
@Test
169162
void getRequiredProperty() {
170163
testProperties.put("exists", "xyz");
171164
assertThat(propertyResolver.getRequiredProperty("exists")).isEqualTo("xyz");
172165

173-
assertThatIllegalStateException().isThrownBy(() ->
174-
propertyResolver.getRequiredProperty("bogus"));
166+
assertThatIllegalStateException().isThrownBy(() -> propertyResolver.getRequiredProperty("bogus"));
175167
}
176168

177169
@Test
178170
void getRequiredProperty_withStringArrayConversion() {
179171
testProperties.put("exists", "abc,123");
180-
assertThat(propertyResolver.getRequiredProperty("exists", String[].class)).isEqualTo(new String[] { "abc", "123" });
172+
assertThat(propertyResolver.getRequiredProperty("exists", String[].class)).containsExactly("abc", "123");
181173

182-
assertThatIllegalStateException().isThrownBy(() ->
183-
propertyResolver.getRequiredProperty("bogus", String[].class));
174+
assertThatIllegalStateException().isThrownBy(() -> propertyResolver.getRequiredProperty("bogus", String[].class));
184175
}
185176

186177
@Test
187178
void resolvePlaceholders() {
188-
MutablePropertySources propertySources = new MutablePropertySources();
189179
propertySources.addFirst(new MockPropertySource().withProperty("key", "value"));
190-
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
191-
assertThat(resolver.resolvePlaceholders("Replace this ${key}")).isEqualTo("Replace this value");
180+
assertThat(propertyResolver.resolvePlaceholders("Replace this ${key}")).isEqualTo("Replace this value");
192181
}
193182

194183
@Test
195184
void resolvePlaceholders_withUnresolvable() {
196-
MutablePropertySources propertySources = new MutablePropertySources();
197185
propertySources.addFirst(new MockPropertySource().withProperty("key", "value"));
198-
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
199-
assertThat(resolver.resolvePlaceholders("Replace this ${key} plus ${unknown}"))
186+
assertThat(propertyResolver.resolvePlaceholders("Replace this ${key} plus ${unknown}"))
200187
.isEqualTo("Replace this value plus ${unknown}");
201188
}
202189

203190
@Test
204191
void resolvePlaceholders_withDefaultValue() {
205-
MutablePropertySources propertySources = new MutablePropertySources();
206192
propertySources.addFirst(new MockPropertySource().withProperty("key", "value"));
207-
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
208-
assertThat(resolver.resolvePlaceholders("Replace this ${key} plus ${unknown:defaultValue}"))
193+
assertThat(propertyResolver.resolvePlaceholders("Replace this ${key} plus ${unknown:defaultValue}"))
209194
.isEqualTo("Replace this value plus defaultValue");
210195
}
211196

212197
@Test
213198
void resolvePlaceholders_withNullInput() {
214-
assertThatIllegalArgumentException().isThrownBy(() ->
215-
new PropertySourcesPropertyResolver(new MutablePropertySources()).resolvePlaceholders(null));
199+
assertThatIllegalArgumentException().isThrownBy(() -> propertyResolver.resolvePlaceholders(null));
216200
}
217201

218202
@Test
219203
void resolveRequiredPlaceholders() {
220-
MutablePropertySources propertySources = new MutablePropertySources();
221204
propertySources.addFirst(new MockPropertySource().withProperty("key", "value"));
222-
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
223-
assertThat(resolver.resolveRequiredPlaceholders("Replace this ${key}")).isEqualTo("Replace this value");
205+
assertThat(propertyResolver.resolveRequiredPlaceholders("Replace this ${key}")).isEqualTo("Replace this value");
224206
}
225207

226208
@Test
227209
void resolveRequiredPlaceholders_withUnresolvable() {
228-
MutablePropertySources propertySources = new MutablePropertySources();
229210
propertySources.addFirst(new MockPropertySource().withProperty("key", "value"));
230-
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
231-
assertThatExceptionOfType(PlaceholderResolutionException.class).isThrownBy(() ->
232-
resolver.resolveRequiredPlaceholders("Replace this ${key} plus ${unknown}"));
211+
assertThatExceptionOfType(PlaceholderResolutionException.class)
212+
.isThrownBy(() -> propertyResolver.resolveRequiredPlaceholders("Replace this ${key} plus ${unknown}"));
233213
}
234214

235215
@Test
236216
void resolveRequiredPlaceholders_withDefaultValue() {
237-
MutablePropertySources propertySources = new MutablePropertySources();
238217
propertySources.addFirst(new MockPropertySource().withProperty("key", "value"));
239-
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
240-
assertThat(resolver.resolveRequiredPlaceholders("Replace this ${key} plus ${unknown:defaultValue}"))
218+
assertThat(propertyResolver.resolveRequiredPlaceholders("Replace this ${key} plus ${unknown:defaultValue}"))
241219
.isEqualTo("Replace this value plus defaultValue");
242220
}
243221

244222
@Test
245223
void resolveRequiredPlaceholders_withNullInput() {
246-
assertThatIllegalArgumentException().isThrownBy(() ->
247-
new PropertySourcesPropertyResolver(new MutablePropertySources()).resolveRequiredPlaceholders(null));
224+
assertThatIllegalArgumentException().isThrownBy(() -> propertyResolver.resolveRequiredPlaceholders(null));
248225
}
249226

250227
@Test
@@ -256,17 +233,17 @@ void setRequiredProperties_andValidateRequiredProperties() {
256233
propertyResolver.setRequiredProperties("foo", "bar");
257234

258235
// neither foo nor bar properties are present -> validating should throw
259-
assertThatExceptionOfType(MissingRequiredPropertiesException.class).isThrownBy(
260-
propertyResolver::validateRequiredProperties)
261-
.withMessage("The following properties were declared as required " +
262-
"but could not be resolved: [foo, bar]");
236+
assertThatExceptionOfType(MissingRequiredPropertiesException.class)
237+
.isThrownBy(propertyResolver::validateRequiredProperties)
238+
.withMessage("The following properties were declared as required " +
239+
"but could not be resolved: [foo, bar]");
263240

264241
// add foo property -> validation should fail only on missing 'bar' property
265242
testProperties.put("foo", "fooValue");
266-
assertThatExceptionOfType(MissingRequiredPropertiesException.class).isThrownBy(
267-
propertyResolver::validateRequiredProperties)
268-
.withMessage("The following properties were declared as required " +
269-
"but could not be resolved: [bar]");
243+
assertThatExceptionOfType(MissingRequiredPropertiesException.class)
244+
.isThrownBy(propertyResolver::validateRequiredProperties)
245+
.withMessage("The following properties were declared as required " +
246+
"but could not be resolved: [bar]");
270247

271248
// add bar property -> validation should pass, even with an empty string value
272249
testProperties.put("bar", "");
@@ -291,13 +268,13 @@ void resolveNestedPropertyPlaceholders() {
291268
assertThat(pr.getProperty("p2")).isEqualTo("v2");
292269
assertThat(pr.getProperty("p3")).isEqualTo("v1:v2");
293270
assertThat(pr.getProperty("p4")).isEqualTo("v1:v2");
294-
assertThatExceptionOfType(PlaceholderResolutionException.class).isThrownBy(() ->
295-
pr.getProperty("p5"))
296-
.withMessageContaining("Could not resolve placeholder 'bogus' in value \"${p1}:${p2}:${bogus}\"");
271+
assertThatExceptionOfType(PlaceholderResolutionException.class)
272+
.isThrownBy(() -> pr.getProperty("p5"))
273+
.withMessageContaining("Could not resolve placeholder 'bogus' in value \"${p1}:${p2}:${bogus}\"");
297274
assertThat(pr.getProperty("p6")).isEqualTo("v1:v2:def");
298-
assertThatExceptionOfType(PlaceholderResolutionException.class).isThrownBy(() ->
299-
pr.getProperty("pL"))
300-
.withMessageContaining("Circular");
275+
assertThatExceptionOfType(PlaceholderResolutionException.class)
276+
.isThrownBy(() -> pr.getProperty("pL"))
277+
.withMessageContaining("Circular");
301278
}
302279

303280
@Test
@@ -349,9 +326,9 @@ void ignoreUnresolvableNestedPlaceholdersIsConfigurable() {
349326

350327
// placeholders nested within the value of "p4" are unresolvable and cause an
351328
// exception by default
352-
assertThatExceptionOfType(PlaceholderResolutionException.class).isThrownBy(() ->
353-
pr.getProperty("p4"))
354-
.withMessageContaining("Could not resolve placeholder 'bogus' in value \"${p1}:${p2}:${bogus}\"");
329+
assertThatExceptionOfType(PlaceholderResolutionException.class)
330+
.isThrownBy(() -> pr.getProperty("p4"))
331+
.withMessageContaining("Could not resolve placeholder 'bogus' in value \"${p1}:${p2}:${bogus}\"");
355332

356333
// relax the treatment of unresolvable nested placeholders
357334
pr.setIgnoreUnresolvableNestedPlaceholders(true);
@@ -361,9 +338,58 @@ void ignoreUnresolvableNestedPlaceholdersIsConfigurable() {
361338
// resolve[Nested]Placeholders methods behave as usual regardless the value of
362339
// ignoreUnresolvableNestedPlaceholders
363340
assertThat(pr.resolvePlaceholders("${p1}:${p2}:${bogus}")).isEqualTo("v1:v2:${bogus}");
364-
assertThatExceptionOfType(PlaceholderResolutionException.class).isThrownBy(() ->
365-
pr.resolveRequiredPlaceholders("${p1}:${p2}:${bogus}"))
366-
.withMessageContaining("Could not resolve placeholder 'bogus' in value \"${p1}:${p2}:${bogus}\"");
341+
assertThatExceptionOfType(PlaceholderResolutionException.class)
342+
.isThrownBy(() -> pr.resolveRequiredPlaceholders("${p1}:${p2}:${bogus}"))
343+
.withMessageContaining("Could not resolve placeholder 'bogus' in value \"${p1}:${p2}:${bogus}\"");
344+
}
345+
346+
347+
@Nested
348+
class EscapedPlaceholderTests {
349+
350+
@Test // gh-34720
351+
void escapedPlaceholdersAreNotEvaluated() {
352+
testProperties.put("prop1", "value1");
353+
testProperties.put("prop2", "value2\\${prop1}");
354+
355+
assertThat(propertyResolver.getProperty("prop2")).isEqualTo("value2${prop1}");
356+
}
357+
358+
@Test // gh-34720
359+
void escapedPlaceholdersAreNotEvaluatedWithCharSequenceValues() {
360+
testProperties.put("prop1", "value1");
361+
testProperties.put("prop2", new StringBuilder("value2\\${prop1}"));
362+
363+
assertThat(propertyResolver.getProperty("prop2")).isEqualTo("value2${prop1}");
364+
}
365+
366+
@Test // gh-34720
367+
void multipleEscapedPlaceholdersArePreserved() {
368+
testProperties.put("prop1", "value1");
369+
testProperties.put("prop2", "value2");
370+
testProperties.put("complex", "start\\${prop1}middle\\${prop2}end");
371+
372+
assertThat(propertyResolver.getProperty("complex")).isEqualTo("start${prop1}middle${prop2}end");
373+
}
374+
375+
@Test // gh-34720
376+
void doubleBackslashesAreProcessedCorrectly() {
377+
testProperties.put("prop1", "value1");
378+
testProperties.put("doubleEscaped", "value2\\\\${prop1}");
379+
380+
assertThat(propertyResolver.getProperty("doubleEscaped")).isEqualTo("value2\\${prop1}");
381+
}
382+
383+
@Test // gh-34720
384+
void escapedPlaceholdersInNestedPropertiesAreNotEvaluated() {
385+
testProperties.put("p1", "v1");
386+
testProperties.put("p2", "v2");
387+
testProperties.put("escaped", "prefix-\\${p1}");
388+
testProperties.put("nested", "${escaped}-${p2}");
389+
390+
assertThat(propertyResolver.getProperty("nested")).isEqualTo("prefix-${p1}-v2");
391+
}
392+
367393
}
368394

369395
}

0 commit comments

Comments
 (0)