Allow caching null objects. (#1303)

Closes #939.

Co-authored-by: mikereiche <michael.reiche@couchbase.com>
This commit is contained in:
Michael Reiche
2022-01-17 14:17:53 -08:00
committed by mikereiche
parent daa35059de
commit c6e1138123
3 changed files with 174 additions and 2 deletions

View File

@@ -106,7 +106,7 @@ public class CouchbaseCache extends AbstractValueAdaptingCache {
name));
}
cacheWriter.put(cacheConfig.getCollectionName(), createCacheKey(key), value, cacheConfig.getExpiry(),
cacheWriter.put(cacheConfig.getCollectionName(), createCacheKey(key), toStoreValue(value), cacheConfig.getExpiry(),
cacheConfig.getValueTranscoder());
}
@@ -116,7 +116,7 @@ public class CouchbaseCache extends AbstractValueAdaptingCache {
return get(key);
}
Object result = cacheWriter.putIfAbsent(cacheConfig.getCollectionName(), createCacheKey(key), value,
Object result = cacheWriter.putIfAbsent(cacheConfig.getCollectionName(), createCacheKey(key), toStoreValue(value),
cacheConfig.getExpiry(), cacheConfig.getValueTranscoder());
if (result == null) {

View File

@@ -0,0 +1,71 @@
/*
* Copyright 2022 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.couchbase.cache;
import java.io.Serializable;
/**
* This is a standalone class (vs. inner) to allow Serialization of all fields to work.
* If it was an inner class of CouchbaseCacheIntegrationTests, then it would have a
* this$0 field = CouchbaseCacheIntegrationTests and would not serialize.
*
* @author Michael Reiche
*/
class CacheUser implements Serializable {
// private static final long serialVersionUID = 8817717605659870262L;
String firstname;
String lastname;
String id;
public CacheUser(String id, String firstname, String lastname) {
this.id = id;
this.firstname = firstname;
this.lastname = lastname;
}
public String getId() {
return id;
}
// define equals for assertEquals()
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (!(o instanceof CacheUser)) {
return false;
}
CacheUser other = (CacheUser) o;
if (id == null && other.id != null) {
return false;
}
if (firstname == null && other.firstname != null) {
return false;
}
if (lastname == null && other.lastname != null) {
return false;
}
return id.equals(other.id) && firstname.equals(other.firstname) && lastname.equals(other.lastname);
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("CacheUser: { id=" + id + ", firstname=" + firstname + ", lastname=" + lastname + "}");
return sb.toString();
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright 2022 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.couchbase.cache;
import static com.couchbase.client.java.query.QueryScanConsistency.REQUEST_PLUS;
import static org.junit.Assert.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.data.couchbase.util.ClusterType;
import org.springframework.data.couchbase.util.IgnoreWhen;
import org.springframework.data.couchbase.util.JavaIntegrationTests;
import com.couchbase.client.java.query.QueryOptions;
/**
* CouchbaseCache tests Theses tests rely on a cb server running.
*
* @author Michael Reiche
*/
@IgnoreWhen(clusterTypes = ClusterType.MOCKED)
class CouchbaseCacheIntegrationTests extends JavaIntegrationTests {
volatile CouchbaseCache cache;
@BeforeEach
@Override
public void beforeEach() {
super.beforeEach();
cache = CouchbaseCacheManager.create(couchbaseTemplate.getCouchbaseClientFactory()).createCouchbaseCache("myCache",
CouchbaseCacheConfiguration.defaultCacheConfig());
clear(cache);
}
private void clear(CouchbaseCache c) {
couchbaseTemplate.getCouchbaseClientFactory().getCluster().query("SELECT count(*) from `" + bucketName() + "`",
QueryOptions.queryOptions().scanConsistency(REQUEST_PLUS));
c.clear();
couchbaseTemplate.getCouchbaseClientFactory().getCluster().query("SELECT count(*) from `" + bucketName() + "`",
QueryOptions.queryOptions().scanConsistency(REQUEST_PLUS));
}
@Test
void cachePutGet() {
CacheUser user1 = new CacheUser(UUID.randomUUID().toString(), "first1", "last1");
CacheUser user2 = new CacheUser(UUID.randomUUID().toString(), "first2", "last2");
assertNull(cache.get(user1.getId())); // was not put -> cacheMiss
cache.put(user1.getId(), user1); // put user1
cache.put(user2.getId(), user2); // put user2
assertEquals(user1, cache.get(user1.getId()).get()); // get user1
assertEquals(user2, cache.get(user2.getId()).get()); // get user2
}
@Test
void cacheEvict() {
CacheUser user1 = new CacheUser(UUID.randomUUID().toString(), "first1", "last1");
CacheUser user2 = new CacheUser(UUID.randomUUID().toString(), "first2", "last2");
cache.put(user1.getId(), user1); // put user1
cache.put(user2.getId(), user2); // put user2
cache.evict(user1.getId()); // evict user1
assertEquals(user2, cache.get(user2.getId()).get()); // get user2 -> present
}
@Test
void cacheHitMiss() {
CacheUser user1 = new CacheUser(UUID.randomUUID().toString(), "first1", "last1");
CacheUser user2 = new CacheUser(UUID.randomUUID().toString(), "first2", "last2");
assertNull(cache.get(user2.getId())); // get user2 -> cacheMiss
cache.put(user1.getId(), null); // cache a null
assertNotNull(cache.get(user1.getId())); // cacheHit null
assertNull(cache.get(user1.getId()).get()); // fetch cached null
}
@Test
void cachePutIfAbsent() {
CacheUser user1 = new CacheUser(UUID.randomUUID().toString(), "first1", "last1");
CacheUser user2 = new CacheUser(UUID.randomUUID().toString(), "first2", "last2");
assertNull(cache.putIfAbsent(user1.getId(), user1)); // should put user1, return null
assertEquals(user1, cache.putIfAbsent(user1.getId(), user2).get()); // should not put user2, should return user1
assertEquals(user1, cache.get(user1.getId()).get()); // user1.getId() is still user1
}
}