From 6d8d345583cb3de46340769f63c0f7b6936aaf79 Mon Sep 17 00:00:00 2001 From: Costin Leau Date: Mon, 29 Nov 2010 19:05:14 +0200 Subject: [PATCH 1/6] + improve serialization of hash items in RedisTemplate + add missing method on HashOperations --- .../core/DefaultBoundHashOperations.java | 3 +- .../keyvalue/redis/core/HashOperations.java | 2 + .../keyvalue/redis/core/RedisTemplate.java | 92 +++++++++++++++---- .../keyvalue/redis/util/DefaultRedisMap.java | 11 +++ 4 files changed, 89 insertions(+), 19 deletions(-) diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/DefaultBoundHashOperations.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/DefaultBoundHashOperations.java index 7639ed704..8387c45be 100644 --- a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/DefaultBoundHashOperations.java +++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/DefaultBoundHashOperations.java @@ -27,7 +27,6 @@ import java.util.Set; class DefaultBoundHashOperations extends DefaultKeyBound implements BoundHashOperations { private final HashOperations ops; - private RedisOperations template; /** * Constructs a new DefaultBoundHashOperations instance. @@ -52,7 +51,7 @@ class DefaultBoundHashOperations extends DefaultKeyBound implement @Override public RedisOperations getOperations() { - return template; + return ops.getOperations(); } @Override diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/HashOperations.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/HashOperations.java index 82618e745..23755be71 100644 --- a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/HashOperations.java +++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/HashOperations.java @@ -43,4 +43,6 @@ public interface HashOperations { void set(H key, HK hashKey, HV value); Collection values(H key); + + RedisOperations getOperations(); } diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java index 01b7d0e70..fd44f0b59 100644 --- a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java +++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java @@ -56,7 +56,8 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation private boolean exposeConnection = false; private RedisSerializer keySerializer = new StringRedisSerializer(); private RedisSerializer valueSerializer = new SimpleRedisSerializer(); - private RedisSerializer defaultSerializer = new SimpleRedisSerializer(); + private RedisSerializer hashKeySerializer = new SimpleRedisSerializer(); + private RedisSerializer hashValueSerializer = new SimpleRedisSerializer(); public RedisTemplate() { } @@ -82,7 +83,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation } public T execute(RedisCallback action, boolean exposeConnection) { - return execute(action, isExposeConnection(), defaultSerializer); + return execute(action, isExposeConnection(), valueSerializer); } public T execute(RedisCallback action, boolean exposeConnection, RedisSerializer returnSerializer) { @@ -133,18 +134,43 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation this.exposeConnection = exposeConnection; } + /** + * Sets the key serializer to be used by this template. Defaults to {@link SimpleRedisSerializer}. + * + * @param serializer + */ public void setKeySerializer(RedisSerializer serializer) { this.keySerializer = serializer; } + /** + * Sets the value serializer to be used by this template. Defaults to {@link SimpleRedisSerializer}. + * + * @param serializer + */ public void setValueSerializer(RedisSerializer serializer) { this.valueSerializer = serializer; } - public void setDefaultSerializer(RedisSerializer serializer) { - this.defaultSerializer = serializer; + /** + * Sets the hash key (or field) serializer to be used by this template. Defaults to {@link SimpleRedisSerializer}. + * + * @param hashKeySerializer The hashKeySerializer to set. + */ + public void setHashKeySerializer(RedisSerializer hashKeySerializer) { + this.hashKeySerializer = hashKeySerializer; } + /** + * Sets the hash value serializer to be used by this template. Defaults to {@link SimpleRedisSerializer}. + * + * @param hashValueSerializer The hashValueSerializer to set. + */ + public void setHashValueSerializer(RedisSerializer hashValueSerializer) { + this.hashValueSerializer = hashValueSerializer; + } + + /** * Invocation handler that suppresses close calls on JDO PersistenceManagers. * Also prepares returned Query objects. @@ -207,7 +233,9 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation Collection values = (List.class.isAssignableFrom(type) ? new ArrayList(rawValues.size()) : new LinkedHashSet(rawValues.size())); for (byte[] bs : rawValues) { - values.add((V) valueSerializer.deserialize(bs)); + if (bs != null) { + values.add((V) valueSerializer.deserialize(bs)); + } } return (T) values; @@ -218,21 +246,49 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation Collection values = (List.class.isAssignableFrom(type) ? new ArrayList(rawValues.size()) : new LinkedHashSet(rawValues.size())); for (byte[] bs : rawValues) { - values.add((H) valueSerializer.deserialize(bs)); + if (bs != null) { + values.add((H) valueSerializer.deserialize(bs)); + } } return values; } + @SuppressWarnings("unchecked") + private K deserializeKey(byte[] value) { + return (K) deserialize(value, keySerializer); + } + + @SuppressWarnings("unchecked") + private V deserializeValue(byte[] value) { + return (V) deserialize(value, valueSerializer); + } + + @SuppressWarnings("unchecked") + private HK deserializeHashKey(byte[] value) { + return (HK) deserialize(value, hashKeySerializer); + } + + @SuppressWarnings("unchecked") + private HV deserializeHashValue(byte[] value) { + return (HV) deserialize(value, hashValueSerializer); + } + + private T deserialize(byte[] value, RedisSerializer serializer) { + if (isEmpty(value)) { + return null; + } + return (T) serializer.deserialize(value); + } + + private static boolean isEmpty(byte[] data) { + return (data == null || data.length == 0); + } + // utility methods for the template internal methods private abstract class ValueDeserializingRedisCallback implements RedisCallback { private K key; - public ValueDeserializingRedisCallback() { - this(null); - - } - public ValueDeserializingRedisCallback(K key) { this.key = key; } @@ -241,10 +297,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation @Override public final V doInRedis(RedisConnection connection) { byte[] result = inRedis(rawKey(key), connection); - if (result != null) { - return (V) valueSerializer.deserialize(result); - } - return null; + return deserializeValue(result); } protected abstract byte[] inRedis(byte[] rawKey, RedisConnection connection); @@ -558,7 +611,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation public void diffAndStore(final K key, K destKey, final K... keys) { final byte[][] rawKeys = rawKeys(aggregateKeys(key, keys)); final byte[] rawDestKey = rawKey(destKey); - Object rawValues = execute(new RedisCallback() { + execute(new RedisCallback() { @Override public Object doInRedis(RedisConnection connection) { connection.sDiffStore(rawDestKey, rawKeys); @@ -881,6 +934,11 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation private class DefaultHashOperations implements HashOperations { + @Override + public RedisOperations getOperations() { + return RedisTemplate.this; + } + @Override public HV get(K key, Object hashKey) { final byte[] rawKey = rawKey(key); @@ -893,7 +951,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation } }, true); - return (HV) valueSerializer.deserialize(rawHashValue); + return deserializeHashValue(rawHashValue); } @Override diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/DefaultRedisMap.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/DefaultRedisMap.java index e1b3440ea..5e84e389f 100644 --- a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/DefaultRedisMap.java +++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/DefaultRedisMap.java @@ -31,10 +31,21 @@ public class DefaultRedisMap implements RedisMap { private final BoundHashOperations hashOps; + /** + * Constructs a new DefaultRedisMap instance. + * + * @param key + * @param operations + */ public DefaultRedisMap(String key, RedisOperations operations) { this.hashOps = operations.forHash(key); } + /** + * Constructs a new DefaultRedisMap instance. + * + * @param boundOps + */ public DefaultRedisMap(BoundHashOperations boundOps) { this.hashOps = boundOps; } From 267285f9fc3bc503ffdd87ee9c61d123b5c90720 Mon Sep 17 00:00:00 2001 From: Costin Leau Date: Mon, 29 Nov 2010 19:10:05 +0200 Subject: [PATCH 2/6] + fix equals/hashcode for redis map + add first draft of integration tests --- .../keyvalue/redis/util/DefaultRedisMap.java | 27 +++ .../redis/util/AbstractRedisMapTests.java | 219 ++++++++++++++++++ .../keyvalue/redis/util/RedisMapTests.java | 66 ++++++ 3 files changed, 312 insertions(+) create mode 100644 spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/util/AbstractRedisMapTests.java create mode 100644 spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/util/RedisMapTests.java diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/DefaultRedisMap.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/DefaultRedisMap.java index 5e84e389f..ff580c50b 100644 --- a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/DefaultRedisMap.java +++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/util/DefaultRedisMap.java @@ -137,4 +137,31 @@ public class DefaultRedisMap implements RedisMap { public Collection values() { return hashOps.values(); } + + @Override + public boolean equals(Object o) { + if (o == this) + return true; + + if (o instanceof RedisMap) { + return o.hashCode() == hashCode(); + } + return false; + } + + @Override + public int hashCode() { + int result = 17 + getClass().hashCode(); + result = result * 31 + getKey().hashCode(); + return result; + } + + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("RedisStore for key:"); + sb.append(getKey()); + return sb.toString(); + } } \ No newline at end of file diff --git a/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/util/AbstractRedisMapTests.java b/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/util/AbstractRedisMapTests.java new file mode 100644 index 000000000..4d0ce897d --- /dev/null +++ b/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/util/AbstractRedisMapTests.java @@ -0,0 +1,219 @@ +/* + * Copyright 2010 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 + * + * http://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.keyvalue.redis.util; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.data.keyvalue.redis.connection.RedisConnection; +import org.springframework.data.keyvalue.redis.connection.RedisConnectionFactory; +import org.springframework.data.keyvalue.redis.core.RedisCallback; +import org.springframework.data.keyvalue.redis.core.RedisOperations; +import org.springframework.data.keyvalue.redis.core.RedisTemplate; + +/** + * Integration test for Redis Map. + * + * @author Costin Leau + */ +@RunWith(Parameterized.class) +public abstract class AbstractRedisMapTests { + + protected RedisMap map; + protected ObjectFactory keyFactory; + protected ObjectFactory valueFactory; + protected RedisTemplate template; + + private static Set connFactories = new LinkedHashSet(); + + abstract RedisMap createMap(); + + @Before + public void setUp() throws Exception { + map = createMap(); + } + + public AbstractRedisMapTests(ObjectFactory keyFactory, ObjectFactory valueFactory, RedisTemplate template) { + this.keyFactory = keyFactory; + this.valueFactory = valueFactory; + this.template = template; + connFactories.add(template.getConnectionFactory()); + } + + @AfterClass + public static void cleanUp() { + if (connFactories != null) { + for (RedisConnectionFactory connectionFactory : connFactories) { + try { + ((DisposableBean) connectionFactory).destroy(); + System.out.println("Succesfully cleaned up factory " + connectionFactory); + } catch (Exception ex) { + System.err.println("Cannot clean factory " + connectionFactory + ex); + } + } + } + } + + protected K getKey() { + return keyFactory.instance(); + } + + protected V getValue() { + return valueFactory.instance(); + } + + protected RedisStore copyStore(RedisStore store) { + return new DefaultRedisMap(store.getKey(), store.getOperations()); + } + + @After + public void tearDown() throws Exception { + // remove the collection entirely since clear() doesn't always work + map.getOperations().delete(map.getKey()); + template.execute(new RedisCallback() { + + @Override + public Object doInRedis(RedisConnection connection) { + connection.flushDb(); + return null; + } + }); + } + + @Test + public void testClear() { + map.clear(); + assertEquals(0, map.size()); + map.put(getKey(), getValue()); + assertEquals(1, map.size()); + map.clear(); + assertEquals(0, map.size()); + } + + @Test + public void testContainsKey() { + K k1 = getKey(); + K k2 = getKey(); + + assertFalse(map.containsKey(k1)); + assertFalse(map.containsKey(k2)); + map.put(k1, getValue()); + assertTrue(map.containsKey(k1)); + map.put(k2, getValue()); + assertTrue(map.containsKey(k2)); + } + + @Test(expected = UnsupportedOperationException.class) + public void testContainsValue() { + V v1 = getValue(); + V v2 = getValue(); + + assertFalse(map.containsValue(v1)); + assertFalse(map.containsValue(v2)); + map.put(getKey(), v1); + assertTrue(map.containsValue(v1)); + map.put(getKey(), v2); + assertTrue(map.containsValue(v2)); + } + + public Set> entrySet() { + return map.entrySet(); + } + + @Test + public void testEquals() { + RedisStore clone = copyStore(map); + assertEquals(clone, map); + assertEquals(clone, clone); + assertEquals(map, map); + } + + @Test + public void testNotEquals() { + RedisOperations ops = map.getOperations(); + RedisStore newInstance = new DefaultRedisMap(ops. forHash(map.getKey() + ":new")); + assertFalse(map.equals(newInstance)); + assertFalse(newInstance.equals(map)); + } + + public V get(Object key) { + return map.get(key); + } + + @Test + public void testGetKey() { + assertNotNull(map.getKey()); + } + + public RedisOperations getOperations() { + return map.getOperations(); + } + + @Test + public void testHashCode() { + assertThat(map.hashCode(), not(equalTo(map.getKey().hashCode()))); + assertEquals(map.hashCode(), copyStore(map).hashCode()); + } + + public Integer increment(K key, int delta) { + return map.increment(key, delta); + } + + public boolean isEmpty() { + return map.isEmpty(); + } + + public Set keySet() { + return map.keySet(); + } + + public V put(K key, V value) { + return map.put(key, value); + } + + public void putAll(Map m) { + map.putAll(m); + } + + public boolean putIfAbsent(K key, V value) { + return map.putIfAbsent(key, value); + } + + public V remove(Object key) { + return map.remove(key); + } + + public int size() { + return map.size(); + } + + public Collection values() { + return map.values(); + } +} \ No newline at end of file diff --git a/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/util/RedisMapTests.java b/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/util/RedisMapTests.java new file mode 100644 index 000000000..ea74a089d --- /dev/null +++ b/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/util/RedisMapTests.java @@ -0,0 +1,66 @@ +/* + * Copyright 2010 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 + * + * http://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.keyvalue.redis.util; + +import java.util.Arrays; +import java.util.Collection; + +import org.junit.runners.Parameterized.Parameters; +import org.springframework.data.keyvalue.redis.Person; +import org.springframework.data.keyvalue.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.data.keyvalue.redis.core.RedisTemplate; + +/** + * Integration test for RedisMap. + * + * @author Costin Leau + */ +public class RedisMapTests extends AbstractRedisMapTests { + + public RedisMapTests(ObjectFactory keyFactory, ObjectFactory valueFactory, RedisTemplate template) { + super(keyFactory, valueFactory, template); + } + + @Override + RedisMap createMap() { + String redisName = getClass().getName(); + return new DefaultRedisMap(redisName, template); + } + + @Parameters + public static Collection testParams() { + // create Jedis Factory + ObjectFactory stringFactory = new StringObjectFactory(); + ObjectFactory personFactory = new PersonObjectFactory(); + + JedisConnectionFactory jedisConnFactory = new JedisConnectionFactory(); + jedisConnFactory.setPooling(false); + jedisConnFactory.afterPropertiesSet(); + + RedisTemplate stringTemplate = new RedisTemplate(jedisConnFactory); + RedisTemplate personTemplate = new RedisTemplate(jedisConnFactory); + + // JredisConnectionFactory jredisConnFactory = new JredisConnectionFactory(); + // jredisConnFactory.setPooling(false); + // jredisConnFactory.afterPropertiesSet(); + // + // RedisTemplate stringTemplateJR = new RedisTemplate(jredisConnFactory); + // RedisTemplate personTemplateJR = new RedisTemplate(jredisConnFactory); + + return Arrays.asList(new Object[][] { { stringFactory, stringFactory, stringTemplate }, + { personFactory, personFactory, personTemplate } }); + } +} \ No newline at end of file From 37c0f8b24285951c7466163c902872c567a04570 Mon Sep 17 00:00:00 2001 From: Costin Leau Date: Mon, 29 Nov 2010 20:18:49 +0200 Subject: [PATCH 3/6] + add proper serialization of hash specific items --- .../keyvalue/redis/core/RedisTemplate.java | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java index fd44f0b59..3a6653a32 100644 --- a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java +++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java @@ -228,6 +228,15 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation return rawKeys; } + private byte[] rawHashKey(HK value) { + return (value != null ? hashKeySerializer.serialize(value) : null); + } + + private byte[] rawHashValue(HV value) { + return (value != null ? hashValueSerializer.serialize(value) : null); + } + + @SuppressWarnings("unchecked") private > T values(Collection rawValues, Class type) { Collection values = (List.class.isAssignableFrom(type) ? new ArrayList(rawValues.size()) @@ -242,12 +251,12 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation } @SuppressWarnings("unchecked") - private Collection arbitraryValues(Collection rawValues, Class type) { + private Collection hashValues(Collection rawValues, Class type) { Collection values = (List.class.isAssignableFrom(type) ? new ArrayList(rawValues.size()) : new LinkedHashSet(rawValues.size())); for (byte[] bs : rawValues) { if (bs != null) { - values.add((H) valueSerializer.deserialize(bs)); + values.add((H) hashValueSerializer.deserialize(bs)); } } @@ -942,7 +951,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation @Override public HV get(K key, Object hashKey) { final byte[] rawKey = rawKey(key); - final byte[] rawHashKey = rawValue(hashKey); + final byte[] rawHashKey = rawHashKey(hashKey); byte[] rawHashValue = execute(new RedisCallback() { @Override @@ -957,7 +966,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation @Override public Boolean hasKey(K key, Object hashKey) { final byte[] rawKey = rawKey(key); - final byte[] rawHashKey = rawValue(hashKey); + final byte[] rawHashKey = rawHashKey(hashKey); return execute(new RedisCallback() { @Override @@ -970,7 +979,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation @Override public Integer increment(K key, HK hashKey, final int delta) { final byte[] rawKey = rawKey(key); - final byte[] rawHashKey = rawValue(hashKey); + final byte[] rawHashKey = rawHashKey(hashKey); return execute(new RedisCallback() { @Override @@ -992,7 +1001,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation } }, true); - return (Set) arbitraryValues(rawValues, Set.class); + return (Set) hashValues(rawValues, Set.class); } @Override @@ -1014,7 +1023,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation final Map hashes = new LinkedHashMap(m.size()); for (Map.Entry entry : hashes.entrySet()) { - hashes.put(rawValue(entry.getKey()), rawValue(entry.getValue())); + hashes.put(rawHashKey(entry.getKey()), rawHashValue(entry.getValue())); } execute(new RedisCallback() { @@ -1029,8 +1038,8 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation @Override public void set(K key, HK hashKey, HV value) { final byte[] rawKey = rawKey(key); - final byte[] rawHashKey = rawValue(hashKey); - final byte[] rawHashValue = rawValue(value); + final byte[] rawHashKey = rawHashKey(hashKey); + final byte[] rawHashValue = rawHashValue(value); execute(new RedisCallback() { @Override @@ -1052,13 +1061,13 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation } }, true); - return (List) arbitraryValues(rawValues, List.class); + return (List) hashValues(rawValues, List.class); } @Override public void delete(K key, Object hashKey) { final byte[] rawKey = rawKey(key); - final byte[] rawHashKey = rawValue(hashKey); + final byte[] rawHashKey = rawHashKey(hashKey); execute(new RedisCallback() { @Override From d1a4b6268aa2b82fc5710a5e1a0538b377ef1bc4 Mon Sep 17 00:00:00 2001 From: Costin Leau Date: Mon, 29 Nov 2010 20:20:51 +0200 Subject: [PATCH 4/6] + fix minor bug that caused the closing proxy to be always used --- .../springframework/data/keyvalue/redis/core/RedisTemplate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java index 3a6653a32..adfaca77a 100644 --- a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java +++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java @@ -83,7 +83,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation } public T execute(RedisCallback action, boolean exposeConnection) { - return execute(action, isExposeConnection(), valueSerializer); + return execute(action, exposeConnection, valueSerializer); } public T execute(RedisCallback action, boolean exposeConnection, RedisSerializer returnSerializer) { From 432e0502a2a80b68bc828d40379a768bad75eeaa Mon Sep 17 00:00:00 2001 From: Costin Leau Date: Mon, 29 Nov 2010 20:24:33 +0200 Subject: [PATCH 5/6] + improve multiSet + all integration tests pass --- .../keyvalue/redis/core/RedisTemplate.java | 6 +- .../redis/util/AbstractRedisMapTests.java | 169 +++++++++++++++--- 2 files changed, 153 insertions(+), 22 deletions(-) diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java index adfaca77a..795d127b4 100644 --- a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java +++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java @@ -1018,11 +1018,15 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation @Override public void multiSet(K key, Map m) { + if (m.isEmpty()) { + return; + } + final byte[] rawKey = rawKey(key); final Map hashes = new LinkedHashMap(m.size()); - for (Map.Entry entry : hashes.entrySet()) { + for (Map.Entry entry : m.entrySet()) { hashes.put(rawHashKey(entry.getKey()), rawHashValue(entry.getValue())); } diff --git a/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/util/AbstractRedisMapTests.java b/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/util/AbstractRedisMapTests.java index 4d0ce897d..857f271ff 100644 --- a/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/util/AbstractRedisMapTests.java +++ b/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/util/AbstractRedisMapTests.java @@ -17,11 +17,15 @@ package org.springframework.data.keyvalue.redis.util; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; +import static org.junit.matchers.JUnitMatchers.*; import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; +import java.util.UUID; import java.util.Map.Entry; import org.junit.After; @@ -31,6 +35,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.springframework.beans.factory.DisposableBean; +import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.keyvalue.redis.connection.RedisConnection; import org.springframework.data.keyvalue.redis.connection.RedisConnectionFactory; import org.springframework.data.keyvalue.redis.core.RedisCallback; @@ -162,8 +167,15 @@ public abstract class AbstractRedisMapTests { assertFalse(newInstance.equals(map)); } - public V get(Object key) { - return map.get(key); + @Test + public void testGet() { + K k1 = getKey(); + V v1 = getValue(); + + assertNull(map.get(UUID.randomUUID())); + assertNull(map.get(k1)); + map.put(k1, v1); + assertEquals(v1, map.get(k1)); } @Test @@ -171,8 +183,9 @@ public abstract class AbstractRedisMapTests { assertNotNull(map.getKey()); } - public RedisOperations getOperations() { - return map.getOperations(); + @Test + public void testGetOperations() { + assertEquals(template, map.getOperations()); } @Test @@ -181,39 +194,153 @@ public abstract class AbstractRedisMapTests { assertEquals(map.hashCode(), copyStore(map).hashCode()); } - public Integer increment(K key, int delta) { - return map.increment(key, delta); + @Test(expected = InvalidDataAccessApiUsageException.class) + public void testIncrement() { + K k1 = getKey(); + V v1 = getValue(); + + map.put(k1, v1); + Integer value = map.increment(k1, 1); + System.out.println("Value is " + value); } - public boolean isEmpty() { - return map.isEmpty(); + @Test + public void testIsEmpty() { + map.clear(); + assertTrue(map.isEmpty()); + map.put(getKey(), getValue()); + assertFalse(map.isEmpty()); + map.clear(); + assertTrue(map.isEmpty()); } - public Set keySet() { - return map.keySet(); + @Test + public void testKeySet() { + map.clear(); + assertTrue(map.keySet().isEmpty()); + K k1 = getKey(); + K k2 = getKey(); + K k3 = getKey(); + + map.put(k1, getValue()); + map.put(k2, getValue()); + map.put(k3, getValue()); + + Iterator iterator = map.keySet().iterator(); + assertEquals(k1, iterator.next()); + assertEquals(k2, iterator.next()); + assertEquals(k3, iterator.next()); + assertFalse(iterator.hasNext()); } - public V put(K key, V value) { - return map.put(key, value); + @Test + public void testPut() { + K k1 = getKey(); + K k2 = getKey(); + V v1 = getValue(); + V v2 = getValue(); + + map.put(k1, v1); + map.put(k2, v2); + + assertEquals(v1, map.get(k1)); + assertEquals(v2, map.get(k2)); } - public void putAll(Map m) { + @Test + public void testPutAll() { + Map m = new LinkedHashMap(); + K k1 = getKey(); + K k2 = getKey(); + + V v1 = getValue(); + V v2 = getValue(); + + m.put(k1, v1); + m.put(k2, v2); + + assertNull(map.get(k1)); + assertNull(map.get(k2)); + map.putAll(m); + + assertEquals(v1, map.get(k1)); + assertEquals(v2, map.get(k2)); } - public boolean putIfAbsent(K key, V value) { - return map.putIfAbsent(key, value); + @Test + public void testPutIfAbsent() { + K k1 = getKey(); + K k2 = getKey(); + + V v1 = getValue(); + V v2 = getValue(); + + assertNull(map.get(k1)); + assertTrue(map.putIfAbsent(k1, v1)); + assertFalse(map.putIfAbsent(k1, v2)); + assertEquals(v1, map.get(k1)); + + assertTrue(map.putIfAbsent(k2, v2)); + assertFalse(map.putIfAbsent(k2, v1)); + + assertEquals(v2, map.get(k2)); } - public V remove(Object key) { - return map.remove(key); + @Test + public void testRemove() { + K k1 = getKey(); + K k2 = getKey(); + + V v1 = getValue(); + V v2 = getValue(); + + assertNull(map.remove(k1)); + assertNull(map.remove(k2)); + + map.put(k1, v1); + map.put(k2, v2); + + assertEquals(v1, map.remove(k1)); + assertNull(map.remove(k1)); + assertNull(map.get(k1)); + + assertEquals(v2, map.remove(k2)); + assertNull(map.remove(k2)); + assertNull(map.get(k2)); } - public int size() { - return map.size(); + @Test + public void testSize() { + assertEquals(0, map.size()); + map.put(getKey(), getValue()); + assertEquals(1, map.size()); + K k = getKey(); + map.put(k, getValue()); + assertEquals(2, map.size()); + map.remove(k); + assertEquals(1, map.size()); + + map.clear(); + assertEquals(0, map.size()); } - public Collection values() { - return map.values(); + @Test + public void testValues() { + V v1 = getValue(); + V v2 = getValue(); + V v3 = getValue(); + + map.put(getKey(), v1); + map.put(getKey(), v2); + + Collection values = map.values(); + assertEquals(2, values.size()); + assertThat(values, hasItems(v1, v2)); + + map.put(getKey(), v3); + values = map.values(); + assertEquals(3, values.size()); + assertThat(values, hasItems(v1, v2, v3)); } } \ No newline at end of file From 7adeeaee2441b3b441486b38b6b9ab201046b0d1 Mon Sep 17 00:00:00 2001 From: Costin Leau Date: Mon, 29 Nov 2010 21:10:10 +0200 Subject: [PATCH 6/6] + fix compilation error on javac compilers --- .../data/keyvalue/redis/core/RedisTemplate.java | 2 +- .../keyvalue/redis/serializer/SimpleRedisSerializer.java | 4 ++-- .../data/keyvalue/redis/util/AbstractRedisMapTests.java | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java index 795d127b4..260a02968 100644 --- a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java +++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/core/RedisTemplate.java @@ -960,7 +960,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation } }, true); - return deserializeHashValue(rawHashValue); + return (HV) deserializeHashValue(rawHashValue); } @Override diff --git a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/serializer/SimpleRedisSerializer.java b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/serializer/SimpleRedisSerializer.java index 1741e38e5..a9edfc0aa 100644 --- a/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/serializer/SimpleRedisSerializer.java +++ b/spring-data-redis/src/main/java/org/springframework/data/keyvalue/redis/serializer/SimpleRedisSerializer.java @@ -31,8 +31,8 @@ public class SimpleRedisSerializer implements RedisSerializer { private Converter serializer = new SerializingConverter(); private Converter deserializer = new DeserializingConverter(); - private sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder(); - private sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder(); + // private sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder(); + // private sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder(); @SuppressWarnings("unchecked") @Override diff --git a/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/util/AbstractRedisMapTests.java b/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/util/AbstractRedisMapTests.java index 857f271ff..5ad668e4f 100644 --- a/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/util/AbstractRedisMapTests.java +++ b/spring-data-redis/src/test/java/org/springframework/data/keyvalue/redis/util/AbstractRedisMapTests.java @@ -343,4 +343,9 @@ public abstract class AbstractRedisMapTests { assertEquals(3, values.size()); assertThat(values, hasItems(v1, v2, v3)); } + + @Test(expected = UnsupportedOperationException.class) + public void testEntrySet() { + map.entrySet(); + } } \ No newline at end of file