Store by value support for ConcurrentMapCacheManager

ConcurrentMapCacheManager and ConcurrentMapCache now support the
serialization of cache entries via a new `storeByValue` attribute. If it is
explicitly enabled, the cache value is first serialized and that content
is stored in the cache.

The net result is that any further change made on the object returned
from the annotated method is not applied on the copy held in the cache.

Issue: SPR-13758
This commit is contained in:
Stephane Nicoll
2015-12-22 09:48:49 +01:00
parent cf20308134
commit 0194988425
5 changed files with 207 additions and 4 deletions

View File

@@ -211,7 +211,7 @@ public abstract class AbstractCacheTests<T extends Cache> {
results.forEach(r -> assertThat(r, is(1))); // Only one method got invoked
}
private String createRandomKey() {
protected String createRandomKey() {
return UUID.randomUUID().toString();
}

View File

@@ -25,6 +25,7 @@ import static org.junit.Assert.*;
/**
* @author Juergen Hoeller
* @author Stephane Nicoll
*/
public class ConcurrentMapCacheManagerTests {
@@ -120,4 +121,21 @@ public class ConcurrentMapCacheManagerTests {
assertNull(cache1y.get("key3"));
}
@Test
public void testChangeStoreByValue() {
ConcurrentMapCacheManager cm = new ConcurrentMapCacheManager("c1", "c2");
assertFalse(cm.isStoreByValue());
Cache cache1 = cm.getCache("c1");
assertTrue(cache1 instanceof ConcurrentMapCache);
assertFalse(((ConcurrentMapCache)cache1).isStoreByValue());
cache1.put("key", "value");
cm.setStoreByValue(true);
assertTrue(cm.isStoreByValue());
Cache cache1x = cm.getCache("c1");
assertTrue(cache1x instanceof ConcurrentMapCache);
assertTrue(cache1x != cache1);
assertNull(cache1x.get("key"));
}
}

View File

@@ -16,13 +16,19 @@
package org.springframework.cache.concurrent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.cache.AbstractCacheTests;
import org.springframework.core.serializer.support.SerializationDelegate;
import static org.junit.Assert.*;
/**
* @author Costin Leau
@@ -53,4 +59,53 @@ public class ConcurrentMapCacheTests extends AbstractCacheTests<ConcurrentMapCac
return this.nativeCache;
}
@Test
public void testIsStoreByReferenceByDefault() {
assertFalse(this.cache.isStoreByValue());
}
@SuppressWarnings("unchecked")
@Test
public void testSerializer() {
ConcurrentMapCache serializeCache = createCacheWithStoreByValue();
assertTrue(serializeCache.isStoreByValue());
Object key = createRandomKey();
List<String> content = new ArrayList<>();
content.addAll(Arrays.asList("one", "two", "three"));
serializeCache.put(key, content);
content.remove(0);
List<String> entry = (List<String>) serializeCache.get(key).get();
assertEquals(3, entry.size());
assertEquals("one", entry.get(0));
}
@Test
public void testNonSerializableContent() {
ConcurrentMapCache serializeCache = createCacheWithStoreByValue();
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Failed to serialize");
thrown.expectMessage(this.cache.getClass().getName());
serializeCache.put(createRandomKey(), this.cache);
}
@Test
public void testInvalidSerializedContent() {
ConcurrentMapCache serializeCache = createCacheWithStoreByValue();
String key = createRandomKey();
this.nativeCache.put(key, "Some garbage");
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Failed to deserialize");
thrown.expectMessage("Some garbage");
serializeCache.get(key);
}
private ConcurrentMapCache createCacheWithStoreByValue() {
return new ConcurrentMapCache(CACHE_NAME, nativeCache, true,
new SerializationDelegate(ConcurrentMapCacheTests.class.getClassLoader()));
}
}