diff --git a/src/main/java/org/springframework/data/redis/cache/RedisCache.java b/src/main/java/org/springframework/data/redis/cache/RedisCache.java index afd70ee64..dde79da42 100644 --- a/src/main/java/org/springframework/data/redis/cache/RedisCache.java +++ b/src/main/java/org/springframework/data/redis/cache/RedisCache.java @@ -91,7 +91,8 @@ class RedisCache implements Cache { public ValueWrapper doInRedis(RedisConnection connection) throws DataAccessException { waitForLock(connection); byte[] bs = connection.get(computeKey(key)); - return (bs == null ? null : new SimpleValueWrapper(template.getValueSerializer().deserialize(bs))); + Object value = template.getValueSerializer() != null ? template.getValueSerializer().deserialize(bs) : bs; + return (bs == null ? null : new SimpleValueWrapper(value)); } }, true); } @@ -104,7 +105,13 @@ class RedisCache implements Cache { public Object doInRedis(RedisConnection connection) throws DataAccessException { waitForLock(connection); connection.multi(); - connection.set(k, template.getValueSerializer().serialize(value)); + byte[] v; + if(template.getValueSerializer() == null && value instanceof byte[]) { + v = (byte[])value; + } else { + v = template.getValueSerializer().serialize(value); + } + connection.set(k, v); connection.zAdd(setName, 0, k); if (expiration > 0) { @@ -171,6 +178,9 @@ class RedisCache implements Cache { } private byte[] computeKey(Object key) { + if(template.getKeySerializer() == null && key instanceof byte[]) { + return (byte[])key; + } byte[] k = template.getKeySerializer().serialize(key); if (prefix == null || prefix.length == 0) diff --git a/src/main/java/org/springframework/data/redis/core/AbstractOperations.java b/src/main/java/org/springframework/data/redis/core/AbstractOperations.java index faf2637be..83da06de4 100644 --- a/src/main/java/org/springframework/data/redis/core/AbstractOperations.java +++ b/src/main/java/org/springframework/data/redis/core/AbstractOperations.java @@ -91,6 +91,9 @@ abstract class AbstractOperations { @SuppressWarnings("unchecked") byte[] rawKey(Object key) { Assert.notNull(key, "non null key required"); + if(keySerializer() == null && key instanceof byte[]) { + return (byte[])key; + } return keySerializer().serialize(key); } @@ -100,17 +103,26 @@ abstract class AbstractOperations { @SuppressWarnings("unchecked") byte[] rawValue(Object value) { + if(valueSerializer() == null && value instanceof byte[]) { + return (byte[])value; + } return valueSerializer().serialize(value); } @SuppressWarnings("unchecked") byte[] rawHashKey(HK hashKey) { Assert.notNull(hashKey, "non null hash key required"); + if(hashKeySerializer() == null && hashKey instanceof byte[]) { + return (byte[])hashKey; + } return hashKeySerializer().serialize(hashKey); } @SuppressWarnings("unchecked") byte[] rawHashValue(HV value) { + if(hashValueSerializer() == null & value instanceof byte[]) { + return (byte[])value; + } return hashValueSerializer().serialize(value); } @@ -145,6 +157,9 @@ abstract class AbstractOperations { @SuppressWarnings("unchecked") Set deserializeValues(Set rawValues) { + if(valueSerializer() == null) { + return (Set)rawValues; + } return SerializationUtils.deserialize(rawValues, valueSerializer()); } @@ -155,23 +170,36 @@ abstract class AbstractOperations { } Set> set = new LinkedHashSet>(rawValues.size()); for (Tuple rawValue : rawValues) { - set.add(new DefaultTypedTuple(valueSerializer().deserialize(rawValue.getValue()), rawValue.getScore())); + Object value = rawValue.getValue(); + if(valueSerializer() != null) { + value = valueSerializer().deserialize(rawValue.getValue()); + } + set.add(new DefaultTypedTuple(value, rawValue.getScore())); } return set; } @SuppressWarnings("unchecked") List deserializeValues(List rawValues) { + if(valueSerializer() == null) { + return (List)rawValues; + } return SerializationUtils.deserialize(rawValues, valueSerializer()); } @SuppressWarnings("unchecked") Set deserializeHashKeys(Set rawKeys) { + if(hashKeySerializer() == null) { + return (Set)rawKeys; + } return SerializationUtils.deserialize(rawKeys, hashKeySerializer()); } @SuppressWarnings("unchecked") List deserializeHashValues(List rawValues) { + if(hashValueSerializer() == null) { + return (List)rawValues; + } return SerializationUtils.deserialize(rawValues, hashValueSerializer()); } @@ -193,11 +221,17 @@ abstract class AbstractOperations { @SuppressWarnings("unchecked") K deserializeKey(byte[] value) { + if(keySerializer() == null) { + return (K) value; + } return (K) keySerializer().deserialize(value); } @SuppressWarnings("unchecked") V deserializeValue(byte[] value) { + if(valueSerializer() == null) { + return (V)value; + } return (V) valueSerializer().deserialize(value); } @@ -207,11 +241,17 @@ abstract class AbstractOperations { @SuppressWarnings( { "unchecked" }) HK deserializeHashKey(byte[] value) { + if(hashKeySerializer() == null) { + return (HK)value; + } return (HK) hashKeySerializer().deserialize(value); } @SuppressWarnings("unchecked") HV deserializeHashValue(byte[] value) { + if(hashValueSerializer() == null) { + return (HV)value; + } return (HV) hashValueSerializer().deserialize(value); } } \ No newline at end of file diff --git a/src/main/java/org/springframework/data/redis/core/DefaultTypedTuple.java b/src/main/java/org/springframework/data/redis/core/DefaultTypedTuple.java index e6c6438ad..a5acead55 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultTypedTuple.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultTypedTuple.java @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.core; +import java.util.Arrays; + import org.springframework.data.redis.core.ZSetOperations.TypedTuple; /** @@ -76,7 +78,12 @@ class DefaultTypedTuple implements TypedTuple { if (other.value != null) return false; } - else if (!value.equals(other.value)) + else if(value instanceof byte[]) { + if(!(other.value instanceof byte[])) { + return false; + } + return Arrays.equals((byte[])value, (byte[])other.value); + } else if (!value.equals(other.value)) return false; return true; } diff --git a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java index 83daae30c..d2a5527ca 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java +++ b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java @@ -74,6 +74,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation private boolean exposeConnection = false; private boolean initialized = false; + private boolean enableDefaultSerializer = true; private RedisSerializer defaultSerializer = new JdkSerializationRedisSerializer(); private RedisSerializer keySerializer = null; @@ -100,26 +101,26 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation super.afterPropertiesSet(); boolean defaultUsed = false; - if (keySerializer == null) { - keySerializer = defaultSerializer; - defaultUsed = true; - } - if (valueSerializer == null) { - valueSerializer = defaultSerializer; - defaultUsed = true; + if(enableDefaultSerializer) { + if (keySerializer == null) { + keySerializer = defaultSerializer; + defaultUsed = true; + } + if (valueSerializer == null) { + valueSerializer = defaultSerializer; + defaultUsed = true; + } + if (hashKeySerializer == null) { + hashKeySerializer = defaultSerializer; + defaultUsed = true; + } + if (hashValueSerializer == null) { + hashValueSerializer = defaultSerializer; + defaultUsed = true; + } } - if (hashKeySerializer == null) { - hashKeySerializer = defaultSerializer; - defaultUsed = true; - } - - if (hashValueSerializer == null) { - hashValueSerializer = defaultSerializer; - defaultUsed = true; - } - - if (defaultUsed) { + if (enableDefaultSerializer && defaultUsed) { Assert.notNull(defaultSerializer, "default serializer null and not all serializers initialized"); } @@ -311,6 +312,24 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation this.exposeConnection = exposeConnection; } + /** + * + * @return Whether or not the default serializer should be used. If not, any serializers not explicilty set + * will remain null and values will not be serialized or deserialized. + */ + public boolean isEnableDefaultSerializer() { + return enableDefaultSerializer; + } + + /** + * + * @param enableDefaultSerializer Whether or not the default serializer should be used. If not, + * any serializers not explicilty set will remain null and values will not be serialized or deserialized. + */ + public void setEnableDefaultSerializer(boolean enableDefaultSerializer) { + this.enableDefaultSerializer = enableDefaultSerializer; + } + /** * Returns the default serializer used by this template. * @@ -425,6 +444,9 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation @SuppressWarnings("unchecked") private byte[] rawKey(Object key) { Assert.notNull(key, "non null key required"); + if(keySerializer == null && key instanceof byte[]) { + return (byte[]) key; + } return keySerializer.serialize(key); } @@ -434,6 +456,9 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation @SuppressWarnings("unchecked") private byte[] rawValue(Object value) { + if(valueSerializer == null && value instanceof byte[]) { + return (byte[]) value; + } return valueSerializer.serialize(value); } @@ -450,7 +475,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation @SuppressWarnings("unchecked") private K deserializeKey(byte[] value) { - return (K) keySerializer.deserialize(value); + return keySerializer != null ? (K) keySerializer.deserialize(value) : (K) value; } @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -461,7 +486,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation } List values = new ArrayList(); for(Object rawValue: rawValues) { - if(rawValue instanceof byte[]) { + if(rawValue instanceof byte[] && valueSerializer != null) { values.add(valueSerializer.deserialize((byte[])rawValue)); } else if(rawValue instanceof List) { // Lists are the only potential Collections of mixed values.... @@ -484,20 +509,24 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation return rawSet; } Object setValue = rawSet.iterator().next(); - if(setValue instanceof byte[]) { + if(setValue instanceof byte[] && valueSerializer != null) { return (SerializationUtils.deserialize((Set)rawSet, valueSerializer)); }else if(setValue instanceof Tuple) { - return deserializeTupleValues(rawSet, valueSerializer); + return convertTupleValues(rawSet, valueSerializer); } else { return rawSet; } } @SuppressWarnings({ "unchecked", "rawtypes" }) - private Set> deserializeTupleValues(Set rawValues, RedisSerializer valueSerializer) { + private Set> convertTupleValues(Set rawValues, RedisSerializer valueSerializer) { Set> set = new LinkedHashSet>(rawValues.size()); for (Tuple rawValue : rawValues) { - set.add(new DefaultTypedTuple(valueSerializer.deserialize(rawValue.getValue()), rawValue.getScore())); + Object value = rawValue.getValue(); + if(valueSerializer != null) { + value = valueSerializer.deserialize(rawValue.getValue()); + } + set.add(new DefaultTypedTuple(value, rawValue.getScore())); } return set; } @@ -652,7 +681,8 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation } }, true); - return SerializationUtils.deserialize(rawKeys, keySerializer); + return keySerializer != null ? SerializationUtils.deserialize(rawKeys, keySerializer) : + rawKeys; } diff --git a/src/main/java/org/springframework/data/redis/serializer/SerializationUtils.java b/src/main/java/org/springframework/data/redis/serializer/SerializationUtils.java index 37427310a..e94257aee 100644 --- a/src/main/java/org/springframework/data/redis/serializer/SerializationUtils.java +++ b/src/main/java/org/springframework/data/redis/serializer/SerializationUtils.java @@ -81,6 +81,7 @@ public abstract class SerializationUtils { return ret; } + @SuppressWarnings("unchecked") public static Map deserialize(Map rawValues, RedisSerializer hashKeySerializer, RedisSerializer hashValueSerializer) { if (rawValues == null) { @@ -88,8 +89,12 @@ public abstract class SerializationUtils { } Map map = new LinkedHashMap(rawValues.size()); for (Map.Entry entry : rawValues.entrySet()) { - map.put((HK) hashKeySerializer.deserialize(entry.getKey()), - (HV) hashValueSerializer.deserialize(entry.getValue())); + // May want to deserialize only key or value + HK key = hashKeySerializer != null ? (HK) hashKeySerializer.deserialize(entry.getKey()) : + (HK) entry.getKey(); + HV value = hashValueSerializer != null ? (HV) hashValueSerializer.deserialize(entry.getValue()) : + (HV) entry.getValue(); + map.put(key, value); } return map; } diff --git a/src/test/java/org/springframework/data/redis/support/collections/RedisMapTests.java b/src/test/java/org/springframework/data/redis/support/collections/RedisMapTests.java index e4aefa61a..2171250dc 100644 --- a/src/test/java/org/springframework/data/redis/support/collections/RedisMapTests.java +++ b/src/test/java/org/springframework/data/redis/support/collections/RedisMapTests.java @@ -24,6 +24,7 @@ import org.springframework.data.redis.LongAsStringObjectFactory; import org.springframework.data.redis.ObjectFactory; import org.springframework.data.redis.Person; import org.springframework.data.redis.PersonObjectFactory; +import org.springframework.data.redis.RawObjectFactory; import org.springframework.data.redis.SettingsUtils; import org.springframework.data.redis.StringObjectFactory; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; @@ -74,6 +75,7 @@ public class RedisMapTests extends AbstractRedisMapTests { ObjectFactory personFactory = new PersonObjectFactory(); ObjectFactory doubleFactory = new DoubleAsStringObjectFactory(); ObjectFactory longFactory = new LongAsStringObjectFactory(); + ObjectFactory rawFactory = new RawObjectFactory(); JedisConnectionFactory jedisConnFactory = new JedisConnectionFactory(); jedisConnFactory.setUsePool(true); @@ -97,6 +99,11 @@ public class RedisMapTests extends AbstractRedisMapTests { jsonPersonTemplate.setHashValueSerializer(jsonStringSerializer); jsonPersonTemplate.afterPropertiesSet(); + RedisTemplate rawTemplate = new RedisTemplate(); + rawTemplate.setEnableDefaultSerializer(false); + rawTemplate.setConnectionFactory(jedisConnFactory); + rawTemplate.afterPropertiesSet(); + // JRedis JredisConnectionFactory jredisConnFactory = new JredisConnectionFactory(new JredisPool( SettingsUtils.getHost(), SettingsUtils.getPort())); @@ -118,6 +125,11 @@ public class RedisMapTests extends AbstractRedisMapTests { jsonPersonTemplateJR.setHashValueSerializer(jsonStringSerializer); jsonPersonTemplateJR.afterPropertiesSet(); + RedisTemplate rawTemplateJR = new RedisTemplate(); + rawTemplateJR.setEnableDefaultSerializer(false); + rawTemplateJR.setConnectionFactory(jredisConnFactory); + rawTemplateJR.afterPropertiesSet(); + // Lettuce LettuceConnectionFactory lettuceConnFactory = new LettuceConnectionFactory(); lettuceConnFactory.setPort(SettingsUtils.getPort()); @@ -144,6 +156,11 @@ public class RedisMapTests extends AbstractRedisMapTests { stringTemplateLtc.setConnectionFactory(lettuceConnFactory); stringTemplateLtc.afterPropertiesSet(); + RedisTemplate rawTemplateLtc = new RedisTemplate(); + rawTemplateLtc.setEnableDefaultSerializer(false); + rawTemplateLtc.setConnectionFactory(lettuceConnFactory); + rawTemplateLtc.afterPropertiesSet(); + // SRP SrpConnectionFactory srpConnFactory = new SrpConnectionFactory(); srpConnFactory.setPort(SettingsUtils.getPort()); @@ -170,6 +187,11 @@ public class RedisMapTests extends AbstractRedisMapTests { stringTemplateSrp.setConnectionFactory(srpConnFactory); stringTemplateSrp.afterPropertiesSet(); + RedisTemplate rawTemplateSrp = new RedisTemplate(); + rawTemplateSrp.setEnableDefaultSerializer(false); + rawTemplateSrp.setConnectionFactory(srpConnFactory); + rawTemplateSrp.afterPropertiesSet(); + return Arrays.asList(new Object[][] { { stringFactory, stringFactory, genericTemplate }, @@ -178,12 +200,14 @@ public class RedisMapTests extends AbstractRedisMapTests { { personFactory, stringFactory, genericTemplate }, { personFactory, stringFactory, xstreamGenericTemplate }, { personFactory, stringFactory, jsonPersonTemplate }, + { rawFactory, rawFactory, rawTemplate}, { stringFactory, stringFactory, genericTemplateJR }, { personFactory, personFactory, genericTemplateJR }, { stringFactory, personFactory, genericTemplateJR }, { personFactory, stringFactory, genericTemplateJR }, { personFactory, stringFactory, xGenericTemplateJR }, { personFactory, stringFactory, jsonPersonTemplateJR }, + { rawFactory, rawFactory, rawTemplateJR}, { stringFactory, stringFactory, genericTemplateLettuce }, { personFactory, personFactory, genericTemplateLettuce }, { stringFactory, personFactory, genericTemplateLettuce }, @@ -192,6 +216,7 @@ public class RedisMapTests extends AbstractRedisMapTests { { personFactory, stringFactory, jsonPersonTemplateLettuce }, { stringFactory, doubleFactory, stringTemplateLtc}, { stringFactory, longFactory, stringTemplateLtc}, + { rawFactory, rawFactory, rawTemplateLtc}, { stringFactory, stringFactory, genericTemplateSrp }, { personFactory, personFactory, genericTemplateSrp }, { stringFactory, personFactory, genericTemplateSrp }, @@ -199,6 +224,7 @@ public class RedisMapTests extends AbstractRedisMapTests { { personFactory, stringFactory, xGenericTemplateSrp }, { stringFactory, doubleFactory, stringTemplateSrp}, { stringFactory, longFactory, stringTemplateSrp}, - { personFactory, stringFactory, jsonPersonTemplateSrp }}); + { personFactory, stringFactory, jsonPersonTemplateSrp }, + { rawFactory, rawFactory, rawTemplateSrp}}); } } \ No newline at end of file