Resolving Redis Serialization Issues in Spring Boot
To integrate Redis into a Spring Boot application, start by including the necessary dependencies in your pom.xml file. The spring-boot-starter-data-redis provides the core integration, while jackson-databind is required for JSON serialization capabilities.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
By default, Spring Boot uses JDK serialization for Redis values, which results in binary data that is hard to read. To store data in a human-readable JSON format, you must configure a custom RedisTemplate bean. The following configuration class sets up a Jackson2JsonRedisSerializer for value serialization and a StringRedisSerializer for keys.
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisCacheConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
// Use Jackson2JsonRedisSerializer to serialize values
Jackson2JsonRedisSerializer<Object> Serializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
Serializer.setObjectMapper(objectMapper);
// String serializer for keys
StringRedisSerializer stringSerializer = new StringRedisSerializer();
template.setKeySerializer(stringSerializer);
template.setValueSerializer(Serializer);
template.setHashKeySerializer(stringSerializer);
template.setHashValueSerializer(Serializer);
template.afterPropertiesSet();
return template;
}
}
With the configuration in place, create a service component to interact with the Redis database. This service encapsulates the RedisTemplate to perform standard operations like saving, retrieving, and deleting data.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
@Component
public class CacheService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public void save(String key, Object data) {
redisTemplate.opsForValue().set(key, data);
}
public Object retrieve(String key) {
return redisTemplate.opsForValue().get(key);
}
public void remove(String key) {
redisTemplate.delete(key);
}
}
Below is a test case verifying the serialization logic. It writes a string value to Redis and reads it back.
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class RedisApplicationTests {
@Autowired
private CacheService cacheService;
@Test
public void testRedisOperations() {
String key = "username";
String value = "adminUser";
cacheService.save(key, value);
System.out.println("Retrieved value: " + cacheService.retrieve(key));
}
}
A critical aspect of this configuration is handling data consistency. When RedisTemplate is configured with a JSON serializer, it writes objects into the database as JSON strings, often including type metadata. If you attempt to retrieve a key using this template that was manually set via a Redis client (e.g., using SET key "plain_text"), the deserialization process will fail. The Jackson parser expects a JSON structure but encounters a raw string, leading to a JsonParseException: Unrecognized token. Therefore, ensure that data read by the application was originally serialized by the same serialization logic to avoid runtime errors.