ConcurrentMapCacheManager recreates caches in case of setAllowNullValues change

Issue: SPR-12026
This commit is contained in:
Juergen Hoeller 2014-07-24 15:06:36 +02:00
parent b75eb60943
commit 78484129f5
2 changed files with 48 additions and 4 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,6 +19,7 @@ package org.springframework.cache.concurrent;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@ -70,6 +71,8 @@ public class ConcurrentMapCacheManager implements CacheManager {
* Specify the set of cache names for this CacheManager's 'static' mode.
* <p>The number of caches and their names will be fixed after a call to this method,
* with no creation of further cache regions at runtime.
* <p>Calling this with a {@code null} collection argument resets the
* mode to 'dynamic', allowing for further creation of caches again.
*/
public void setCacheNames(Collection<String> cacheNames) {
if (cacheNames != null) {
@ -78,6 +81,9 @@ public class ConcurrentMapCacheManager implements CacheManager {
}
this.dynamic = false;
}
else {
this.dynamic = true;
}
}
/**
@ -85,9 +91,17 @@ public class ConcurrentMapCacheManager implements CacheManager {
* in this cache manager.
* <p>Default is "true", despite ConcurrentHashMap itself not supporting {@code null}
* values. An internal holder object will be used to store user-level {@code null}s.
* <p>Note: A change of the null-value setting will reset all existing caches,
* if any, to reconfigure them with the new null-value requirement.
*/
public void setAllowNullValues(boolean allowNullValues) {
this.allowNullValues = allowNullValues;
if (allowNullValues != this.allowNullValues) {
this.allowNullValues = allowNullValues;
// Need to recreate all Cache instances with the new null-value configuration...
for (Map.Entry<String, Cache> entry : this.cacheMap.entrySet()) {
entry.setValue(createConcurrentMapCache(entry.getKey()));
}
}
}
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -56,7 +56,7 @@ public class ConcurrentMapCacheManagerTests {
@Test
public void testStaticMode() {
CacheManager cm = new ConcurrentMapCacheManager("c1", "c2");
ConcurrentMapCacheManager cm = new ConcurrentMapCacheManager("c1", "c2");
Cache cache1 = cm.getCache("c1");
assertTrue(cache1 instanceof ConcurrentMapCache);
Cache cache1again = cm.getCache("c1");
@ -76,6 +76,36 @@ public class ConcurrentMapCacheManagerTests {
assertNull(cache1.get("key3").get());
cache1.evict("key3");
assertNull(cache1.get("key3"));
cm.setAllowNullValues(false);
Cache cache1x = cm.getCache("c1");
assertTrue(cache1x instanceof ConcurrentMapCache);
assertTrue(cache1x != cache1);
Cache cache2x = cm.getCache("c2");
assertTrue(cache2x instanceof ConcurrentMapCache);
assertTrue(cache2x != cache2);
Cache cache3x = cm.getCache("c3");
assertNull(cache3x);
cache1x.put("key1", "value1");
assertEquals("value1", cache1x.get("key1").get());
cache1x.put("key2", 2);
assertEquals(2, cache1x.get("key2").get());
try {
cache1x.put("key3", null);
fail("Should have thrown NullPointerException");
}
catch (NullPointerException ex) {
// expected
}
cm.setAllowNullValues(true);
Cache cache1y = cm.getCache("c1");
cache1y.put("key3", null);
assertNull(cache1y.get("key3").get());
cache1y.evict("key3");
assertNull(cache1y.get("key3"));
}
}