Add putIfAbsent on Cache abstraction

This commit adds a putIfAbsent method to the Cache interface. This
method offers an atomic put if the key is not already associated in
the cache.

Issue: SPR-11400
This commit is contained in:
Stephane Nicoll
2014-02-12 14:41:34 +01:00
parent 8ed490c4d7
commit 3e74d3b2fb
12 changed files with 332 additions and 54 deletions

View File

@@ -80,6 +80,33 @@ public interface Cache {
*/
void put(Object key, Object value);
/**
* Atomically associate the specified value with the specified key in this cache if
* it is not set already.
* <p>This is equivalent to:
* <pre><code>
* Object existingValue = cache.get(key);
* if (existingValue == null) {
* cache.put(key, value);
* return null;
* } else {
* return existingValue;
* }
* </code></pre>
* except that the action is performed atomically. While all known providers are
* able to perform the put atomically, the returned value may be retrieved after
* the attempt to put (i.e. in a non atomic way). Check the documentation of
* the native cache implementation that you are using for more details.
* @param key the key with which the specified value is to be associated
* @param value the value to be associated with the specified key
* @return the value to which this cache maps the specified key (which may
* be {@code null} itself), or also {@code null} if the cache did not contain
* any mapping for that key prior to this call. Returning {@code null} is
* therefore an indicator that the given {@code value} has been associated
* with the key
*/
ValueWrapper putIfAbsent(Object key, Object value);
/**
* Evict the mapping for this key from this cache if it is present.
* @param key the key whose mapping is to be removed from the cache

View File

@@ -103,7 +103,7 @@ public class ConcurrentMapCache implements Cache {
@Override
public ValueWrapper get(Object key) {
Object value = this.store.get(key);
return (value != null ? new SimpleValueWrapper(fromStoreValue(value)) : null);
return toWrapper(value);
}
@Override
@@ -121,6 +121,12 @@ public class ConcurrentMapCache implements Cache {
this.store.put(key, toStoreValue(value));
}
@Override
public ValueWrapper putIfAbsent(Object key, Object value) {
Object existing = this.store.putIfAbsent(key, value);
return toWrapper(existing);
}
@Override
public void evict(Object key) {
this.store.remove(key);
@@ -158,6 +164,9 @@ public class ConcurrentMapCache implements Cache {
return userValue;
}
private ValueWrapper toWrapper(Object value) {
return (value != null ? new SimpleValueWrapper(fromStoreValue(value)) : null);
}
@SuppressWarnings("serial")
private static class NullHolder implements Serializable {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -34,6 +34,7 @@ import org.springframework.cache.CacheManager;
* <p>Will simply accept any items into the cache not actually storing them.
*
* @author Costin Leau
* @author Stephane Nicoll
* @since 3.1
* @see CompositeCacheManager
*/
@@ -111,6 +112,11 @@ public class NoOpCacheManager implements CacheManager {
@Override
public void put(Object key, Object value) {
}
@Override
public ValueWrapper putIfAbsent(Object key, Object value) {
return null;
}
}
}