We try to use the Spring Data CrudRepository
in our project to provide persistency for our domain objects.
For a start I chose REDIS as backend since in a first experiment with a CrudRepository<ExperimentDomainObject, String>
it seemd, getting it running is easy.
When trying to put it in our production code, things got more complicated, because here our domain objects were not necesseriliy using a simple type as key so the repository was CrudRepository<TestObject, ObjectId>
.
Now I got the exception:
No converter found capable of converting from type [...ObjectId] to type [byte[]]
Searching for this exception, this answer which led my to uneducated experimenting with the RedisTemplate
configuration. (For my experiment I am using emdedded-redis)
My idea was, to provide a RedisTemplate<Object, Object>
instead of RedisTemplate<String, Object>
to allow using the Jackson2JsonRedisSerializer
to do the work as keySerializer also.
Still, calling testRepository.save(testObject)
fails.
Please see my code:
I have public fields and left out the imports for the brevity of this example. If they are required (to make this a MVCE) I will happily provide them. Just leave me a comment.
dependencies:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
implementation group: 'redis.clients', name: "jedis", version: '2.9.0'
implementation group: 'it.ozimov', name: 'embedded-redis', version: '0.7.2'
}
RedisConfiguration:
@Configuration
@EnableRedisRepositories
public class RedisConfiguration {
@Bean
JedisConnectionFactory jedisConnectionFactory() {
return new JedisConnectionFactory();
}
@Bean
public RedisTemplate<Object, Object> redisTemplate() {
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
final RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(jedisConnectionFactory());
template.setDefaultSerializer(jackson2JsonRedisSerializer);
template.setKeySerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setEnableDefaultSerializer(true);
return template;
}
}
TestObject
@RedisHash("test")
public class TestObject
{
@Id public ObjectId testId;
public String value;
public TestObject(ObjectId id, String value)
{
this.testId = id;
this.value = value; // In experiment this is: "magic"
}
}
ObjectId
@EqualsAndHashCode
public class ObjectId {
public String creator; // In experiment, this is "me"
public String name; // In experiment, this is "fool"
}
TestRepository
@Repository
public interface TestRepository extends CrudRepository<TestObject, ObjectId>
{
}
EmbeddedRedisConfiguration
@Configuration
public class EmbeddedRedisConfiguration
{
private final redis.embedded.RedisServer redisServer;
EmbeddedRedisConfiguration(RedisProperties redisProperties)
{
this.redisServer = new redis.embedded.RedisServer(redisProperties.getPort());
}
@PostConstruct
public void init()
{
redisServer.start();
}
@PreDestroy
public void shutdown()
{
redisServer.stop();
}
}
Application:
@SpringBootApplication
public class ExperimentApplication
{
public static void main(String[] args)
{
SpringApplication.run(ExperimentApplication.class, args);
}
}
Not the desired Answer:
Of course, I might introduce some special ID which is a simple datatype, e.g. a JSON-String which I build manually using jacksons ObjectMapper and then use a CrudRepository<TestObject, String>
.
What I also tried in the meantime:
RedisTemplate<String, String>
RedisTemplate<String, Object>
- Autowireing a
RedisTemplate
and setting its default serializer - Registering a
Converter<ObjectId, byte[]>
to- An autowired
ConverterRegistry
- An autowired
GenericConversionService
but apparently they have been the wrong ones.
- An autowired