When I am inserting object to redis, I am using spring annotation and when I try to get the object I am using redis template implementation. While doing so, I am getting exception.
Below is the spring annotation based caching:
@CachePut(value = "API", key = "#key")
public Object upsert(String key, Object value) {
return value;
}
@Cacheable(value = "API", key = "#key")
public Object get(String key) {
return null;
}
Below is the redis template based implementation:
public Object getValue(String key) {
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
return valueOperations.get(key);
}
public void setValue(String key, Object value) {
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
valueOperations.set(key, value);
}
If I use @CachePut with redisTemplate.opsForValue().get(), I am getting excecption as:
Caused by: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('¬' (code 172)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
at [Source: (byte[])"��\u0000\u0005t\u0000\u0002US"; line: 1, column: 2]
If I use redisTemplate.opsForValue().set() with @Cacheable, I am getting exception as:
nested exception is .springframework.data.redis.serializer.SerializationException: Cannot deserialize;
nested exception is .springframework.core.serializer.support.SerializationFailedException:
Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?;
nested exception is java.io.StreamCorruptedException:
invalid stream header: 22547275] with root cause
I am doing this experiment because I am working on a legacy project where spring-annotation based caching implementation is present. Now I have a usecase to do the bulk query for multiple keys. I want to use MGET using redis template, but it throws the first exception mentioned above, as its similar to redisTemplate.opsForValue().get():
protected List<Object> multiGet(List<String> keys) {
List<Object> cachedDataList = new ArrayList<>();
try {
List<Object> cacheObjects = redisTemplate.opsForValue().multiGet(keys);
if (cacheObjects != null) {
cachedDataList.addAll(cacheObjects);
} else {
log.debug("getStateCacheDataBatch: null values for {}", keys);
}
} catch (Exception e) {
log.error("Error while fetching batch state cached data for keys {}", keys, e);
}
return cachedDataList;
}
I have same config for both, so it should be using same for serialization.
@Bean
RedisTemplate<String, Object> redisTemplate(@Autowired RedisConnectionFactory redisConnectionFactory) {
final RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
return template;
}
Need suugestion on this.
When I am inserting object to redis, I am using spring annotation and when I try to get the object I am using redis template implementation. While doing so, I am getting exception.
Below is the spring annotation based caching:
@CachePut(value = "API", key = "#key")
public Object upsert(String key, Object value) {
return value;
}
@Cacheable(value = "API", key = "#key")
public Object get(String key) {
return null;
}
Below is the redis template based implementation:
public Object getValue(String key) {
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
return valueOperations.get(key);
}
public void setValue(String key, Object value) {
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
valueOperations.set(key, value);
}
If I use @CachePut with redisTemplate.opsForValue().get(), I am getting excecption as:
Caused by: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('¬' (code 172)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
at [Source: (byte[])"��\u0000\u0005t\u0000\u0002US"; line: 1, column: 2]
If I use redisTemplate.opsForValue().set() with @Cacheable, I am getting exception as:
nested exception is .springframework.data.redis.serializer.SerializationException: Cannot deserialize;
nested exception is .springframework.core.serializer.support.SerializationFailedException:
Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?;
nested exception is java.io.StreamCorruptedException:
invalid stream header: 22547275] with root cause
I am doing this experiment because I am working on a legacy project where spring-annotation based caching implementation is present. Now I have a usecase to do the bulk query for multiple keys. I want to use MGET using redis template, but it throws the first exception mentioned above, as its similar to redisTemplate.opsForValue().get():
protected List<Object> multiGet(List<String> keys) {
List<Object> cachedDataList = new ArrayList<>();
try {
List<Object> cacheObjects = redisTemplate.opsForValue().multiGet(keys);
if (cacheObjects != null) {
cachedDataList.addAll(cacheObjects);
} else {
log.debug("getStateCacheDataBatch: null values for {}", keys);
}
} catch (Exception e) {
log.error("Error while fetching batch state cached data for keys {}", keys, e);
}
return cachedDataList;
}
I have same config for both, so it should be using same for serialization.
@Bean
RedisTemplate<String, Object> redisTemplate(@Autowired RedisConnectionFactory redisConnectionFactory) {
final RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
return template;
}
Need suugestion on this.
Share Improve this question asked Mar 25 at 20:26 HappsHapps 1258 bronze badges 3- There already is a Redis based implementation for the cache, why implement your own? I get the feeling something is missing here. – M. Deinum Commented Mar 25 at 20:51
- @M.Deinum As I mentioned, in my legacy project CachePut, Cacheable annotation is present for caching. Now I want to implement the multiGet, as there is no annotion available for the same, hence I am using redisTemplate.opsForValue().multiGet(keys). But it is throwing the exception – Happs Commented Mar 25 at 21:02
- Those annotations are from Spring afaik unless you have some AOP etc. that does something with those annotations. – M. Deinum Commented Mar 26 at 8:01
1 Answer
Reset to default 0I found the solution.
The annotation(CachePut, Cacheable) are from Spring and they are using JdkSerializationRedisSerializer for serializing the object. And I have configured redisTemplate with GenericJackson2JsonRedisSerializer.
If I use CachePut
to store an object and redisTemplate
to retrieve it, an exception will be thrown due to a compatibility mismatch between the two serializers.
To resolve I have configured redisTemplate with JdkSerializationRedisSerializer and it worked.
@Bean("customRedisTemplate")
RedisTemplate<String, Object> customRedisTemplate(@Autowired RedisConnectionFactory redisConnectionFactory) {
final RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new JdkSerializationRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(new JdkSerializationRedisSerializer());
return template;
}