Skip to content

Commit 2a2a8d3

Browse files
committed
Allow null values to be cached with @CacheResult
Even though the JSR-107 spec forbids to store null values, our cache abstraction allows that behaviour with a special handled (and this is the default behaviour). While this was working fine with our own set of annotations, the JSR-107 interceptor counterpart was interpreting the spec sensu strictu. We now allow for that special case as well. Issue: SPR-13641
1 parent 59b6600 commit 2a2a8d3

File tree

13 files changed

+86
-10
lines changed

13 files changed

+86
-10
lines changed

spring-aspects/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ public Object cache(Object arg1) {
3838
return counter.getAndIncrement();
3939
}
4040

41+
@Override
42+
public Object cacheNull(Object arg1) {
43+
return null;
44+
}
45+
4146
@Override
4247
public Object conditional(int field) {
4348
return null;

spring-aspects/src/test/java/org/springframework/cache/config/AnnotatedJCacheableService.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 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.
@@ -58,6 +58,12 @@ public Long cache(String id) {
5858
return counter.getAndIncrement();
5959
}
6060

61+
@Override
62+
@CacheResult
63+
public Long cacheNull(String id) {
64+
return null;
65+
}
66+
6167
@Override
6268
@CacheResult(exceptionCacheName = "exception", nonCachedExceptions = NullPointerException.class)
6369
public Long cacheWithException(@CacheKey String id, boolean matchFilter) {

spring-aspects/src/test/java/org/springframework/cache/config/CacheableService.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 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.
@@ -26,6 +26,8 @@ public interface CacheableService<T> {
2626

2727
T cache(Object arg1);
2828

29+
T cacheNull(Object arg1);
30+
2931
void invalidate(Object arg1);
3032

3133
void evictEarly(Object arg1);

spring-aspects/src/test/java/org/springframework/cache/config/DefaultCacheableService.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ public Long cache(Object arg1) {
4040
return counter.getAndIncrement();
4141
}
4242

43+
@Override
44+
@Cacheable("testCache")
45+
public Long cacheNull(Object arg1) {
46+
return null;
47+
}
48+
4349
@Override
4450
@CacheEvict("testCache")
4551
public void invalidate(Object arg1) {

spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/CacheResultInterceptor.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 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.
@@ -59,9 +59,7 @@ protected Object invoke(CacheOperationInvocationContext<CacheResultOperation> co
5959

6060
try {
6161
Object invocationResult = invoker.invoke();
62-
if (invocationResult != null) {
63-
cache.put(cacheKey, invocationResult);
64-
}
62+
cache.put(cacheKey, invocationResult);
6563
return invocationResult;
6664
}
6765
catch (CacheOperationInvoker.ThrowableWrapper ex) {

spring-context-support/src/test/java/org/springframework/cache/jcache/config/AbstractJCacheAnnotationTests.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 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.
@@ -67,6 +67,23 @@ public void cache() {
6767
assertSame(first, second);
6868
}
6969

70+
@Test
71+
public void cacheNull() {
72+
Cache cache = getCache(DEFAULT_CACHE);
73+
74+
String keyItem = name.getMethodName();
75+
assertNull(cache.get(keyItem));
76+
77+
Object first = service.cacheNull(keyItem);
78+
Object second = service.cacheNull(keyItem);
79+
assertSame(first, second);
80+
81+
Cache.ValueWrapper wrapper = cache.get(keyItem);
82+
assertNotNull(wrapper);
83+
assertSame(first, wrapper.get());
84+
assertNull("Cached value should be null", wrapper.get());
85+
}
86+
7087
@Test
7188
public void cacheException() {
7289
String keyItem = name.getMethodName();

spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheableService.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 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.
@@ -25,6 +25,8 @@ public interface JCacheableService<T> {
2525

2626
T cache(String id);
2727

28+
T cacheNull(String id);
29+
2830
T cacheWithException(String id, boolean matchFilter);
2931

3032
T cacheWithCheckedException(String id, boolean matchFilter) throws IOException;

spring-context-support/src/test/java/org/springframework/cache/jcache/interceptor/AnnotatedJCacheableService.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 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.
@@ -57,6 +57,12 @@ public Long cache(String id) {
5757
return counter.getAndIncrement();
5858
}
5959

60+
@Override
61+
@CacheResult
62+
public Long cacheNull(String id) {
63+
return null;
64+
}
65+
6066
@Override
6167
@CacheResult(exceptionCacheName = "exception", nonCachedExceptions = NullPointerException.class)
6268
public Long cacheWithException(@CacheKey String id, boolean matchFilter) {

spring-context/src/test/java/org/springframework/cache/config/AbstractAnnotationTests.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,21 @@ public void testCacheable(CacheableService<?> service) throws Exception {
8989
assertSame(r1, r3);
9090
}
9191

92+
public void testCacheableNull(CacheableService<?> service) throws Exception {
93+
Object o1 = new Object();
94+
assertNull(cm.getCache("testCache").get(o1));
95+
96+
Object r1 = service.cacheNull(o1);
97+
Object r2 = service.cacheNull(o1);
98+
Object r3 = service.cacheNull(o1);
99+
100+
assertSame(r1, r2);
101+
assertSame(r1, r3);
102+
103+
assertEquals(r3, cm.getCache("testCache").get(o1).get());
104+
assertNull("Cached value should be null", r3);
105+
}
106+
92107
public void testEvict(CacheableService<?> service) throws Exception {
93108
Object o1 = new Object();
94109

@@ -457,6 +472,11 @@ public void testCacheable() throws Exception {
457472
testCacheable(cs);
458473
}
459474

475+
@Test
476+
public void testCacheableNull() throws Exception {
477+
testCacheableNull(cs);
478+
}
479+
460480
@Test
461481
public void testInvalidate() throws Exception {
462482
testEvict(cs);

spring-context/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ public Object cache(Object arg1) {
4040
return counter.getAndIncrement();
4141
}
4242

43+
@Override
44+
public Object cacheNull(Object arg1) {
45+
return null;
46+
}
47+
4348
@Override
4449
public Object conditional(int field) {
4550
return null;

spring-context/src/test/java/org/springframework/cache/config/CacheableService.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 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.
@@ -27,6 +27,8 @@ public interface CacheableService<T> {
2727

2828
T cache(Object arg1);
2929

30+
T cacheNull(Object arg1);
31+
3032
void invalidate(Object arg1);
3133

3234
void evictEarly(Object arg1);

spring-context/src/test/java/org/springframework/cache/config/DefaultCacheableService.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ public Long cache(Object arg1) {
4141
return counter.getAndIncrement();
4242
}
4343

44+
@Override
45+
@Cacheable("testCache")
46+
public Long cacheNull(Object arg1) {
47+
return null;
48+
}
49+
4450
@Override
4551
@CacheEvict("testCache")
4652
public void invalidate(Object arg1) {

spring-context/src/test/resources/org/springframework/cache/config/cache-advice.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<cache:advice id="cacheAdviceInterface" cache-manager="cacheManager">
1111
<cache:caching cache="testCache">
1212
<cache:cacheable method="cache"/>
13+
<cache:cacheable method="cacheNull"/>
1314
<cache:cacheable method="conditional" condition="#classField == 3"/>
1415
<cache:cacheable method="unless" unless="#result > 10"/>
1516
<cache:cacheable method="key" key="#p0"/>

0 commit comments

Comments
 (0)