Skip to content

Commit d716bbc

Browse files
committed
Allow caching null objects. (#1303)
Closes #939. Co-authored-by: mikereiche <[email protected]>
1 parent 5b959e7 commit d716bbc

File tree

3 files changed

+174
-2
lines changed

3 files changed

+174
-2
lines changed

src/main/java/org/springframework/data/couchbase/cache/CouchbaseCache.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public void put(final Object key, final Object value) {
106106
name));
107107
}
108108

109-
cacheWriter.put(cacheConfig.getCollectionName(), createCacheKey(key), value, cacheConfig.getExpiry(),
109+
cacheWriter.put(cacheConfig.getCollectionName(), createCacheKey(key), toStoreValue(value), cacheConfig.getExpiry(),
110110
cacheConfig.getValueTranscoder());
111111
}
112112

@@ -116,7 +116,7 @@ public ValueWrapper putIfAbsent(final Object key, final Object value) {
116116
return get(key);
117117
}
118118

119-
Object result = cacheWriter.putIfAbsent(cacheConfig.getCollectionName(), createCacheKey(key), value,
119+
Object result = cacheWriter.putIfAbsent(cacheConfig.getCollectionName(), createCacheKey(key), toStoreValue(value),
120120
cacheConfig.getExpiry(), cacheConfig.getValueTranscoder());
121121

122122
if (result == null) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright 2022 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+
* https://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+
package org.springframework.data.couchbase.cache;
17+
18+
import java.io.Serializable;
19+
20+
/**
21+
* This is a standalone class (vs. inner) to allow Serialization of all fields to work.
22+
* If it was an inner class of CouchbaseCacheIntegrationTests, then it would have a
23+
* this$0 field = CouchbaseCacheIntegrationTests and would not serialize.
24+
*
25+
* @author Michael Reiche
26+
*/
27+
class CacheUser implements Serializable {
28+
// private static final long serialVersionUID = 8817717605659870262L;
29+
String firstname;
30+
String lastname;
31+
String id;
32+
33+
public CacheUser(String id, String firstname, String lastname) {
34+
this.id = id;
35+
this.firstname = firstname;
36+
this.lastname = lastname;
37+
}
38+
39+
public String getId() {
40+
return id;
41+
}
42+
43+
// define equals for assertEquals()
44+
public boolean equals(Object o) {
45+
if (o == null) {
46+
return false;
47+
}
48+
if (!(o instanceof CacheUser)) {
49+
return false;
50+
}
51+
52+
CacheUser other = (CacheUser) o;
53+
if (id == null && other.id != null) {
54+
return false;
55+
}
56+
if (firstname == null && other.firstname != null) {
57+
return false;
58+
}
59+
if (lastname == null && other.lastname != null) {
60+
return false;
61+
}
62+
return id.equals(other.id) && firstname.equals(other.firstname) && lastname.equals(other.lastname);
63+
}
64+
65+
public String toString() {
66+
StringBuffer sb = new StringBuffer();
67+
sb.append("CacheUser: { id=" + id + ", firstname=" + firstname + ", lastname=" + lastname + "}");
68+
return sb.toString();
69+
}
70+
71+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright 2022 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+
* https://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.data.couchbase.cache;
18+
19+
import static com.couchbase.client.java.query.QueryScanConsistency.REQUEST_PLUS;
20+
import static org.junit.Assert.assertNotNull;
21+
import static org.junit.jupiter.api.Assertions.assertEquals;
22+
import static org.junit.jupiter.api.Assertions.assertNull;
23+
24+
import java.util.UUID;
25+
26+
import org.junit.jupiter.api.BeforeEach;
27+
import org.junit.jupiter.api.Test;
28+
import org.springframework.data.couchbase.util.ClusterType;
29+
import org.springframework.data.couchbase.util.IgnoreWhen;
30+
import org.springframework.data.couchbase.util.JavaIntegrationTests;
31+
32+
import com.couchbase.client.java.query.QueryOptions;
33+
34+
/**
35+
* CouchbaseCache tests Theses tests rely on a cb server running.
36+
*
37+
* @author Michael Reiche
38+
*/
39+
@IgnoreWhen(clusterTypes = ClusterType.MOCKED)
40+
class CouchbaseCacheIntegrationTests extends JavaIntegrationTests {
41+
42+
volatile CouchbaseCache cache;
43+
44+
@BeforeEach
45+
@Override
46+
public void beforeEach() {
47+
super.beforeEach();
48+
cache = CouchbaseCacheManager.create(couchbaseTemplate.getCouchbaseClientFactory()).createCouchbaseCache("myCache",
49+
CouchbaseCacheConfiguration.defaultCacheConfig());
50+
clear(cache);
51+
}
52+
53+
private void clear(CouchbaseCache c) {
54+
couchbaseTemplate.getCouchbaseClientFactory().getCluster().query("SELECT count(*) from `" + bucketName() + "`",
55+
QueryOptions.queryOptions().scanConsistency(REQUEST_PLUS));
56+
c.clear();
57+
couchbaseTemplate.getCouchbaseClientFactory().getCluster().query("SELECT count(*) from `" + bucketName() + "`",
58+
QueryOptions.queryOptions().scanConsistency(REQUEST_PLUS));
59+
}
60+
61+
@Test
62+
void cachePutGet() {
63+
CacheUser user1 = new CacheUser(UUID.randomUUID().toString(), "first1", "last1");
64+
CacheUser user2 = new CacheUser(UUID.randomUUID().toString(), "first2", "last2");
65+
assertNull(cache.get(user1.getId())); // was not put -> cacheMiss
66+
cache.put(user1.getId(), user1); // put user1
67+
cache.put(user2.getId(), user2); // put user2
68+
assertEquals(user1, cache.get(user1.getId()).get()); // get user1
69+
assertEquals(user2, cache.get(user2.getId()).get()); // get user2
70+
}
71+
72+
@Test
73+
void cacheEvict() {
74+
CacheUser user1 = new CacheUser(UUID.randomUUID().toString(), "first1", "last1");
75+
CacheUser user2 = new CacheUser(UUID.randomUUID().toString(), "first2", "last2");
76+
cache.put(user1.getId(), user1); // put user1
77+
cache.put(user2.getId(), user2); // put user2
78+
cache.evict(user1.getId()); // evict user1
79+
assertEquals(user2, cache.get(user2.getId()).get()); // get user2 -> present
80+
}
81+
82+
@Test
83+
void cacheHitMiss() {
84+
CacheUser user1 = new CacheUser(UUID.randomUUID().toString(), "first1", "last1");
85+
CacheUser user2 = new CacheUser(UUID.randomUUID().toString(), "first2", "last2");
86+
assertNull(cache.get(user2.getId())); // get user2 -> cacheMiss
87+
cache.put(user1.getId(), null); // cache a null
88+
assertNotNull(cache.get(user1.getId())); // cacheHit null
89+
assertNull(cache.get(user1.getId()).get()); // fetch cached null
90+
}
91+
92+
@Test
93+
void cachePutIfAbsent() {
94+
CacheUser user1 = new CacheUser(UUID.randomUUID().toString(), "first1", "last1");
95+
CacheUser user2 = new CacheUser(UUID.randomUUID().toString(), "first2", "last2");
96+
assertNull(cache.putIfAbsent(user1.getId(), user1)); // should put user1, return null
97+
assertEquals(user1, cache.putIfAbsent(user1.getId(), user2).get()); // should not put user2, should return user1
98+
assertEquals(user1, cache.get(user1.getId()).get()); // user1.getId() is still user1
99+
}
100+
101+
}

0 commit comments

Comments
 (0)