title: SpringData Redis Repository with complex key
body: <p>We try to use the Spring Data <code>CrudRepository</code> in our project to provide persistency for our domain objects.<br>
  For a start I chose REDIS as backend since in a first experiment with a <code>CrudRepository&lt;ExperimentDomainObject, String&gt;</code> it seemd, getting it running is easy.</p>
  
  <p>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 <code>CrudRepository&lt;TestObject, ObjectId&gt;</code>.</p>
  
  <p>Now I got the exception:</p>
  
  <blockquote>
    <p>No converter found capable of converting from type [...ObjectId] to type [byte[]]</p>
  </blockquote>
  
  <p>Searching for this exception, <a href="https://stackoverflow.com/questions/53119756/org-springframework-core-convert-converternotfoundexception-no-converter-found">this answer</a> which led my to uneducated experimenting with the <code>RedisTemplate</code> configuration. (For my experiment I am using emdedded-redis)</p>
  
  <p>My idea was, to provide a <code>RedisTemplate&lt;Object, Object&gt;</code> instead of <code>RedisTemplate&lt;String, Object&gt;</code> to allow using the <code>Jackson2JsonRedisSerializer</code> to do the work as keySerializer also.</p>
  
  <p>Still, calling <code>testRepository.save(testObject)</code> fails.</p>
  
  <p>Please see my code:</p>
  
  <p><em>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.</em></p>
  
  <blockquote>
    <p>dependencies:</p>
  </blockquote>
  
  <pre><code>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'
  }
  </code></pre>
  
  <blockquote>
    <p>RedisConfiguration:</p>
  </blockquote>
  
  <pre><code>@Configuration
  @EnableRedisRepositories
  public class RedisConfiguration {
      @Bean
      JedisConnectionFactory jedisConnectionFactory() {
          return new JedisConnectionFactory();
      }
  
      @Bean
      public RedisTemplate&lt;Object, Object&gt; redisTemplate() {
          Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
  
          final RedisTemplate&lt;Object, Object&gt; template = new RedisTemplate&lt;&gt;();
          template.setConnectionFactory(jedisConnectionFactory());
          template.setDefaultSerializer(jackson2JsonRedisSerializer);
          template.setKeySerializer(jackson2JsonRedisSerializer);
          template.setHashValueSerializer(jackson2JsonRedisSerializer);
          template.setValueSerializer(jackson2JsonRedisSerializer);
          template.setEnableDefaultSerializer(true);
  
          return template;
      }
  }
  </code></pre>
  
  <blockquote>
    <p>TestObject</p>
  </blockquote>
  
  <pre><code>@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"
      }
  }
  </code></pre>
  
  <blockquote>
    <p>ObjectId</p>
  </blockquote>
  
  <pre><code>@EqualsAndHashCode
  public class ObjectId {
      public String creator; // In experiment, this is "me"
      public String name;    // In experiment, this is "fool"
  }
  </code></pre>
  
  <blockquote>
    <p>TestRepository</p>
  </blockquote>
  
  <pre><code>@Repository
  public interface TestRepository extends CrudRepository&lt;TestObject, ObjectId&gt;
  {
  }
  </code></pre>
  
  <blockquote>
    <p>EmbeddedRedisConfiguration</p>
  </blockquote>
  
  <pre><code>@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();
      }
  }
  </code></pre>
  
  <blockquote>
    <p>Application:</p>
  </blockquote>
  
  <pre><code>@SpringBootApplication
  public class ExperimentApplication
  {
      public static void main(String[] args)
      {
          SpringApplication.run(ExperimentApplication.class, args);
      }
  }
  </code></pre>
  
  <h1>Not the desired Answer:</h1>
  
  <p>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 <code>CrudRepository&lt;TestObject, String&gt;</code>.</p>
  
  <h1>What I also tried in the meantime:</h1>
  
  <ul>
  <li><code>RedisTemplate&lt;String, String&gt;</code></li>
  <li><code>RedisTemplate&lt;String, Object&gt;</code></li>
  <li>Autowireing a <code>RedisTemplate</code> and setting its default serializer</li>
  <li>Registering a <code>Converter&lt;ObjectId, byte[]&gt;</code> to
  
  <ul>
  <li>An autowired <code>ConverterRegistry</code></li>
  <li>An autowired <code>GenericConversionService</code><br>
  <em>but apparently they have been the wrong ones</em>.</li>
  </ul></li>
  </ul>