I'm using redis cache on my spring boot application and i need to store an unknown type of response object into redisTemplate. so i'm using kryoSerialzation on my redisTemplates,
Exception :
org.objenesis.ObjenesisException: java.io.NotSerializableException: class sample.data.redis.model.Student not serializable
at org.objenesis.strategy.SerializingInstantiatorStrategy.newInstantiatorOf(SerializingInstantiatorStrategy.java:58)
at com.esotericsoftware.kryo.Kryo.newInstantiator(Kryo.java:1127)
at com.esotericsoftware.kryo.Kryo.newInstance(Kryo.java:1136)
Note:
I couldn't implements Serializable interface on my response object, since its dynamic and unknown type on my application
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>4.0.1</version>
</dependency>
KryoRedisSerializer.java
public class KryoRedisSerializer implements RedisSerializer<Object>{
private final ThreadLocal<Kryo> kryoThreadLocal = new ThreadLocal<Kryo>() {
@Override
protected Kryo initialValue() {
Kryo kryo = new Kryo();
kryo.register(Object.class);
return kryo;
}
};
public KryoRedisSerializer() {
kryoThreadLocal.get().setInstantiatorStrategy((InstantiatorStrategy) new SerializingInstantiatorStrategy());
}
@Override
public byte[] serialize(Object object) throws SerializationException {
// TODO Auto-generated method stub
if (object == null) {
return new byte[0];
}
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
Output output = new Output(outputStream);
kryoThreadLocal.get().writeClassAndObject(output, object);
return output.toBytes();
} catch (IOException e) {
throw new SerializationException("Failed Serialization", e);
}
}
@Override
public Object deserialize(byte[] bytes) throws SerializationException {
// TODO Auto-generated method stub
if (bytes == null || bytes.length == 0) {
return null;
}
try (Input input = new Input(bytes)) {
return kryoThreadLocal.get().readClassAndObject(input);
}
}
}
}
SpringRadisConfig.java
@Configuration
public class SpringRadisConfig {
@Bean
public JedisConnectionFactory connectionFactory() {
JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
connectionFactory.setHostName("localhost");
connectionFactory.setPort(6379);
return connectionFactory;
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(kryoRedisSSerializer());
redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public RedisSerializer<Object> kryoRedisSSerializer() {
return new KryoRedisSSerializer();
}
}
SampleRedisApplication.java (main method)
@SpringBootApplication
@ComponentScan(basePackages = "sample.data.redis")
public class SampleRedisApplication implements CommandLineRunner {
@Autowired
private StringRedisTemplate template;
@Autowired
private SpringRadisConfig redisConfig;
@Override
public void run(String... args) throws Exception {/*
ValueOperations<String, String> ops = this.template.opsForValue();
String key = "spring.boot.redis.test";
if (!this.template.hasKey(key)) {
ops.set(key, "Hi Ratheesh ");
}
System.out.println("Found key " + key + ", value=" + ops.get(key));*/
RedisTemplate<String, Object> redisTemplate = redisConfig.redisTemplate();
ValueOperations<String, Object> values = redisTemplate.opsForValue();
try {
Student student = new Student(1L, "Vishal");
values.set("student", student);
Student std = (Student) values.get("student");
System.out.println(std.getId());
System.out.println(std.getName());
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
// Close the context so it doesn't stay awake listening for redis
SpringApplication.run(SampleRedisApplication.class, args).close();
}
}
Assume student is the response object which i'm getting from remote API, actually i don't have any model object definition(POJO) on my application for API response, because my API response type is (Type T) ie dynamic nodes
I found a solution in github but that is not working (convert object to array and store it Redis)