Skip to content

Commit 3e1b163

Browse files
committed
Merge pull request #13344 from fahimfarookme
* pr/13344: Polish "Fix caching issues with map property sources" Fix caching issues with map property sources
2 parents 461202b + dc1c459 commit 3e1b163

File tree

3 files changed

+76
-10
lines changed

3 files changed

+76
-10
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SpringIterableConfigurationPropertySource.java

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818

1919
import java.util.ArrayList;
2020
import java.util.Collections;
21+
import java.util.HashSet;
2122
import java.util.Iterator;
2223
import java.util.List;
24+
import java.util.Set;
2325
import java.util.stream.Stream;
2426

2527
import org.springframework.core.env.EnumerablePropertySource;
@@ -129,25 +131,18 @@ private PropertyMapping[] getPropertyMappings(Cache cache) {
129131
}
130132

131133
private Cache getCache() {
132-
Object cacheKey = getCacheKey();
134+
CacheKey cacheKey = CacheKey.get(getPropertySource());
133135
if (cacheKey == null) {
134136
return null;
135137
}
136138
if (ObjectUtils.nullSafeEquals(cacheKey, this.cacheKey)) {
137139
return this.cache;
138140
}
139141
this.cache = new Cache();
140-
this.cacheKey = cacheKey;
142+
this.cacheKey = cacheKey.copy();
141143
return this.cache;
142144
}
143145

144-
private Object getCacheKey() {
145-
if (getPropertySource() instanceof MapPropertySource) {
146-
return ((MapPropertySource) getPropertySource()).getSource().keySet();
147-
}
148-
return getPropertySource().getPropertyNames();
149-
}
150-
151146
@Override
152147
protected EnumerablePropertySource<?> getPropertySource() {
153148
return (EnumerablePropertySource<?>) super.getPropertySource();
@@ -177,4 +172,48 @@ public void setMappings(PropertyMapping[] mappings) {
177172

178173
}
179174

175+
private static final class CacheKey {
176+
177+
private Object key;
178+
179+
private CacheKey(Object key) {
180+
this.key = key;
181+
}
182+
183+
public CacheKey copy() {
184+
return new CacheKey(copyKey(this.key));
185+
}
186+
187+
private Object copyKey(Object key) {
188+
if (key instanceof Set) {
189+
return new HashSet<Object>((Set<?>) key);
190+
}
191+
return ((String[]) key).clone();
192+
}
193+
194+
@Override
195+
public int hashCode() {
196+
return this.key.hashCode();
197+
}
198+
199+
@Override
200+
public boolean equals(Object obj) {
201+
if (this == obj) {
202+
return true;
203+
}
204+
if (obj == null || getClass() != obj.getClass()) {
205+
return false;
206+
}
207+
return ObjectUtils.nullSafeEquals(this.key, ((CacheKey) obj).key);
208+
}
209+
210+
public static CacheKey get(EnumerablePropertySource<?> source) {
211+
if (source instanceof MapPropertySource) {
212+
return new CacheKey(((MapPropertySource) source).getSource().keySet());
213+
}
214+
return new CacheKey(source.getPropertyNames());
215+
}
216+
217+
}
218+
180219
}

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
* @author Andy Wilkinson
7777
* @author Stephane Nicoll
7878
* @author Ben Hale
79+
* @author Fahim Farook
7980
*/
8081
@RunWith(ModifiedClassPathRunner.class)
8182
@ClassPathExclusions("log4j*.jar")
@@ -500,12 +501,23 @@ public void systemPropertiesAreSetForLoggingConfiguration() {
500501
@Test
501502
public void environmentPropertiesIgnoreUnresolvablePlaceholders() {
502503
// gh-7719
504+
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
505+
"logging.pattern.console=console ${doesnotexist}");
506+
this.initializer.initialize(this.context.getEnvironment(),
507+
this.context.getClassLoader());
508+
assertThat(System.getProperty(LoggingSystemProperties.CONSOLE_LOG_PATTERN))
509+
.isEqualTo("console ${doesnotexist}");
510+
}
511+
512+
@Test
513+
public void environmentPropertiesResolvePlaceholders() {
503514
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,
504515
"logging.pattern.console=console ${pid}");
505516
this.initializer.initialize(this.context.getEnvironment(),
506517
this.context.getClassLoader());
507518
assertThat(System.getProperty(LoggingSystemProperties.CONSOLE_LOG_PATTERN))
508-
.isEqualTo("console ${pid}");
519+
.isEqualTo(this.context.getEnvironment()
520+
.getProperty("logging.pattern.console"));
509521
}
510522

511523
@Test

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringIterableConfigurationPropertySourceTests.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
*
3838
* @author Phillip Webb
3939
* @author Madhura Bhave
40+
* @author Fahim Farook
4041
*/
4142
public class SpringIterableConfigurationPropertySourceTests {
4243

@@ -157,6 +158,20 @@ public void containsDescendantOfShouldCheckSourceNames() {
157158
.isEqualTo(ConfigurationPropertyState.ABSENT);
158159
}
159160

161+
@Test
162+
public void propertySourceKeyDataChangeInvalidatesCache() {
163+
// gh-13344
164+
Map<String, Object> map = new LinkedHashMap<>();
165+
map.put("key1", "value1");
166+
map.put("key2", "value2");
167+
EnumerablePropertySource<?> source = new MapPropertySource("test", map);
168+
SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(
169+
source, DefaultPropertyMapper.INSTANCE);
170+
assertThat(adapter.stream().count()).isEqualTo(2);
171+
map.put("key3", "value3");
172+
assertThat(adapter.stream().count()).isEqualTo(3);
173+
}
174+
160175
/**
161176
* Test {@link PropertySource} that's also an {@link OriginLookup}.
162177
*/

0 commit comments

Comments
 (0)