如何使用Micronaut框架在Redis中存储POJO?

时间:2019-05-14 07:53:28

标签: java redis micronaut

我是Micronaut的新手。我正在尝试将项目移植到Micronaut(v1.1.1),但发现Redis有问题。

我只是想在Redis中保存一个简单的POJO,但是当我尝试“保存”它时会出现以下错误:

io.lettuce.core.RedisException: io.netty.handler.codec.EncoderException: Cannot encode command. Please close the connection as the connection state may be out of sync.

代码非常简单(HERE,您可以找到完整的测试。):

class DummyTest {
  @Test
  public void testIssue() throws Exception {

    final Date now = Date.from(Instant.now());
    CatalogContent expectedContentOne = CatalogContent.builder()
            .contentId(1)
            .status(ContentStatus.AVAILABLE)
            .title("uno")
            .streamId(1)
            .available(now)
            .tags(Set.of("tag1", "tag2"))
            .build();
    repository.save(expectedContentOne);
  }
}
  /.../

class CatalogContentRepository {
    private StatefulRedisConnection<String, CatalogContent> connection;

    public CatalogContentRepository(StatefulRedisConnection<String, CatalogContent> connection) {
        this.connection = connection;
    } 
    public void save(CatalogContent content) {
        RedisCommands<String, CatalogContent> redisApi = connection.sync();
        redisApi.set(String.valueOf(content.getContentId()),content); //Error here!
    }
}

任何想法都会受到欢迎。

谢谢。

1 个答案:

答案 0 :(得分:0)

记录下来,我将回答我自己的问题:

现在(20190514)Micronaut仅使用硬编码的UTF8字符串编解码器生成StatefulRedisConnection<String,String>。 要更改此设置,您必须替换DefaultRedisClientFactory并定义一个返回所需的StatefulRedisConnection的方法, 使用您喜欢的编解码器。

就我而言:

@Requires(beans = DefaultRedisConfiguration.class)
@Singleton
@Factory
@Replaces(factory = DefaultRedisClientFactory.class)
public class RedisClientFactory extends AbstractRedisClientFactory {

  @Bean(preDestroy = "shutdown")
  @Singleton
  @Primary
  @Override
  public RedisClient redisClient(@Primary AbstractRedisConfiguration config) {
    return super.redisClient(config);
  }


  @Bean(preDestroy = "close")
  @Singleton
  @Primary
  public StatefulRedisConnection<String, Object> myRedisConnection(@Primary RedisClient redisClient) {
    return redisClient.connect(new SerializedObjectCodec());
  }

  @Bean(preDestroy = "close")
  @Singleton
  @Primary
  @Override
  public StatefulRedisConnection<String, String> redisConnection(@Primary RedisClient redisClient) {
    throw new RuntimeException("puta mierda");
  }


  @Override
  @Bean(preDestroy = "close")
  @Singleton
  public StatefulRedisPubSubConnection<String, String> redisPubSubConnection(@Primary RedisClient redisClient) {
    return super.redisPubSubConnection(redisClient);
  }
}

编解码器取自Redis Lettuce wiki

public class SerializedObjectCodec implements RedisCodec<String, Object> {
  private Charset charset = Charset.forName("UTF-8");

  @Override
  public String decodeKey(ByteBuffer bytes) {
    return charset.decode(bytes).toString();
  }

  @Override
  public Object decodeValue(ByteBuffer bytes) {
    try {
      byte[] array = new byte[bytes.remaining()];
      bytes.get(array);
      ObjectInputStream is = new ObjectInputStream(new ByteArrayInputStream(array));
      return is.readObject();
    } catch (Exception e) {
      return null;
    }
  }

  @Override
  public ByteBuffer encodeKey(String key) {
    return charset.encode(key);
  }

  @Override
  public ByteBuffer encodeValue(Object value) {
    try {
      ByteArrayOutputStream bytes = new ByteArrayOutputStream();
      ObjectOutputStream os = new ObjectOutputStream(bytes);
      os.writeObject(value);
      return ByteBuffer.wrap(bytes.toByteArray());
    } catch (IOException e) {
      return null;
    }
  }
}