Skip to content

Commit 1c74a1a

Browse files
committed
Improve allowNullValue handling when a null value is provided
This commit improves `AbstractValueAdaptingCache` to throw a dedicated exception if `allowNullValues` is `false` and a `null` value is provided anyway. This avoid a lower-level exception from the cache library that will miss some context. Issue: SPR-15173
1 parent 2fe5064 commit 1c74a1a

File tree

8 files changed

+109
-32
lines changed

8 files changed

+109
-32
lines changed

spring-context-support/src/test/java/org/springframework/cache/caffeine/CaffeineCacheManagerTests.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,7 @@ public void testStaticMode() {
102102
assertEquals("value1", cache1x.get("key1").get());
103103
cache1x.put("key2", 2);
104104
assertEquals(2, cache1x.get("key2").get());
105-
try {
106-
cache1x.put("key3", null);
107-
fail("Should have thrown NullPointerException");
108-
}
109-
catch (NullPointerException ex) {
110-
// expected
111-
}
112-
105+
113106
cm.setAllowNullValues(true);
114107
Cache cache1y = cm.getCache("c1");
115108

spring-context-support/src/test/java/org/springframework/cache/caffeine/CaffeineCacheTests.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2017 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 org.junit.Test;
2222

2323
import org.springframework.cache.AbstractCacheTests;
24+
import org.springframework.cache.AbstractValueAdaptingCacheTests;
2425
import org.springframework.cache.Cache;
2526

2627
import static org.junit.Assert.*;
@@ -29,21 +30,31 @@
2930
* @author Ben Manes
3031
* @author Stephane Nicoll
3132
*/
32-
public class CaffeineCacheTests extends AbstractCacheTests<CaffeineCache> {
33+
public class CaffeineCacheTests extends AbstractValueAdaptingCacheTests<CaffeineCache> {
3334

3435
private com.github.benmanes.caffeine.cache.Cache<Object, Object> nativeCache;
3536

3637
private CaffeineCache cache;
3738

39+
private CaffeineCache cacheNoNull;
40+
3841
@Before
3942
public void setUp() {
4043
nativeCache = Caffeine.newBuilder().build();
4144
cache = new CaffeineCache(CACHE_NAME, nativeCache);
45+
com.github.benmanes.caffeine.cache.Cache<Object, Object> nativeCacheNoNull
46+
= Caffeine.newBuilder().build();
47+
cacheNoNull = new CaffeineCache(CACHE_NAME_NO_NULL, nativeCacheNoNull, false);
4248
}
4349

4450
@Override
4551
protected CaffeineCache getCache() {
46-
return cache;
52+
return getCache(true);
53+
}
54+
55+
@Override
56+
protected CaffeineCache getCache(boolean allowNull) {
57+
return allowNull ? this.cache : this.cacheNoNull;
4758
}
4859

4960
@Override

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

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2017 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,25 +26,32 @@
2626
import org.junit.Before;
2727

2828
import org.springframework.cache.AbstractCacheTests;
29+
import org.springframework.cache.AbstractValueAdaptingCacheTests;
2930

3031
/**
3132
* @author Stephane Nicoll
3233
*/
33-
public class JCacheEhCacheApiTests extends AbstractCacheTests<JCacheCache> {
34+
public class JCacheEhCacheApiTests extends AbstractValueAdaptingCacheTests<JCacheCache> {
3435

3536
private CacheManager cacheManager;
3637

3738
private Cache<Object, Object> nativeCache;
3839

3940
private JCacheCache cache;
4041

42+
private JCacheCache cacheNoNull;
43+
4144

4245
@Before
4346
public void setup() {
4447
this.cacheManager = getCachingProvider().getCacheManager();
4548
this.cacheManager.createCache(CACHE_NAME, new MutableConfiguration<>());
49+
this.cacheManager.createCache(CACHE_NAME_NO_NULL, new MutableConfiguration<>());
4650
this.nativeCache = this.cacheManager.getCache(CACHE_NAME);
4751
this.cache = new JCacheCache(this.nativeCache);
52+
Cache<Object, Object> nativeCacheNoNull =
53+
this.cacheManager.getCache(CACHE_NAME_NO_NULL);
54+
this.cacheNoNull = new JCacheCache(nativeCacheNoNull, false);
4855
}
4956

5057
protected CachingProvider getCachingProvider() {
@@ -58,10 +65,13 @@ public void shutdown() {
5865
}
5966
}
6067

61-
6268
@Override
6369
protected JCacheCache getCache() {
64-
return this.cache;
70+
return getCache(true);
71+
}
72+
73+
@Override protected JCacheCache getCache(boolean allowNull) {
74+
return allowNull ? this.cache : this.cacheNoNull;
6575
}
6676

6777
@Override

spring-context/src/main/java/org/springframework/cache/support/AbstractValueAdaptingCache.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2017 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.
@@ -95,8 +95,13 @@ protected Object fromStoreValue(Object storeValue) {
9595
* @return the value to store
9696
*/
9797
protected Object toStoreValue(Object userValue) {
98-
if (this.allowNullValues && userValue == null) {
99-
return NullValue.INSTANCE;
98+
if (userValue == null) {
99+
if (this.allowNullValues) {
100+
return NullValue.INSTANCE;
101+
}
102+
throw new IllegalArgumentException(
103+
String.format("Cache '%s' is configured to not allow null " +
104+
"values but null was provided", getName()));
100105
}
101106
return userValue;
102107
}

spring-context/src/test/java/org/springframework/cache/AbstractCacheTests.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2017 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 @@
2626
import org.junit.Test;
2727
import org.junit.rules.ExpectedException;
2828

29+
import org.springframework.cache.support.AbstractValueAdaptingCache;
30+
2931
import static org.hamcrest.core.Is.*;
3032
import static org.junit.Assert.*;
3133

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2002-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cache;
18+
19+
import org.junit.Rule;
20+
import org.junit.Test;
21+
import org.junit.rules.ExpectedException;
22+
23+
import org.springframework.cache.support.AbstractValueAdaptingCache;
24+
25+
/**
26+
*
27+
* @author Stephane Nicoll
28+
*/
29+
public abstract class AbstractValueAdaptingCacheTests<T extends AbstractValueAdaptingCache>
30+
extends AbstractCacheTests<T> {
31+
32+
@Rule
33+
public ExpectedException thrown = ExpectedException.none();
34+
35+
protected final static String CACHE_NAME_NO_NULL = "testCacheNoNull";
36+
37+
protected abstract T getCache(boolean allowNull);
38+
39+
@Test
40+
public void testCachePutNullValueAllowNullFalse() {
41+
T cache = getCache(false);
42+
String key = createRandomKey();
43+
44+
this.thrown.expect(IllegalArgumentException.class);
45+
this.thrown.expectMessage(CACHE_NAME_NO_NULL);
46+
this.thrown.expectMessage(
47+
"is configured to not allow null values but null was provided");
48+
cache.put(key, null);
49+
}
50+
51+
}

spring-context/src/test/java/org/springframework/cache/concurrent/ConcurrentMapCacheManagerTests.java

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2017 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.
@@ -104,14 +104,7 @@ public void testStaticMode() {
104104
assertEquals("value1", cache1x.get("key1").get());
105105
cache1x.put("key2", 2);
106106
assertEquals(2, cache1x.get("key2").get());
107-
try {
108-
cache1x.put("key3", null);
109-
fail("Should have thrown NullPointerException");
110-
}
111-
catch (NullPointerException ex) {
112-
// expected
113-
}
114-
107+
115108
cm.setAllowNullValues(true);
116109
Cache cache1y = cm.getCache("c1");
117110

spring-context/src/test/java/org/springframework/cache/concurrent/ConcurrentMapCacheTests.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2017 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,7 +25,7 @@
2525
import org.junit.Before;
2626
import org.junit.Test;
2727

28-
import org.springframework.cache.AbstractCacheTests;
28+
import org.springframework.cache.AbstractValueAdaptingCacheTests;
2929
import org.springframework.core.serializer.support.SerializationDelegate;
3030

3131
import static org.junit.Assert.*;
@@ -35,23 +35,35 @@
3535
* @author Juergen Hoeller
3636
* @author Stephane Nicoll
3737
*/
38-
public class ConcurrentMapCacheTests extends AbstractCacheTests<ConcurrentMapCache> {
38+
public class ConcurrentMapCacheTests
39+
extends AbstractValueAdaptingCacheTests<ConcurrentMapCache> {
3940

4041
protected ConcurrentMap<Object, Object> nativeCache;
4142

4243
protected ConcurrentMapCache cache;
4344

45+
protected ConcurrentMap<Object, Object> nativeCacheNoNull;
46+
47+
protected ConcurrentMapCache cacheNoNull;
48+
4449

4550
@Before
4651
public void setUp() throws Exception {
4752
this.nativeCache = new ConcurrentHashMap<>();
4853
this.cache = new ConcurrentMapCache(CACHE_NAME, this.nativeCache, true);
54+
this.nativeCacheNoNull = new ConcurrentHashMap<>();
55+
this.cacheNoNull = new ConcurrentMapCache(CACHE_NAME_NO_NULL,
56+
this.nativeCacheNoNull, false);
4957
this.cache.clear();
5058
}
5159

5260
@Override
5361
protected ConcurrentMapCache getCache() {
54-
return this.cache;
62+
return getCache(true);
63+
}
64+
65+
@Override protected ConcurrentMapCache getCache(boolean allowNull) {
66+
return allowNull ? this.cache : this.cacheNoNull;
5567
}
5668

5769
@Override

0 commit comments

Comments
 (0)