How to get hash value using key on spring data redis? - redis

On redis I have added key S000, and I want load hash object with that key.
I always get NULL from even I passed the correct key.
How can I do that, please find screenshot below for more detail.
Thank!
#Configuration
#EnableRedisRepositories
public class RedisConfig {
#Bean
public JedisConnectionFactory connectionFactory() {
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
configuration.setHostName("localhost");
configuration.setPort(9000);
return new JedisConnectionFactory(configuration);
}
#Bean
public RedisTemplate<String, User> redisTemplate() {
RedisTemplate<String, User> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setEnableTransactionSupport(true);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
#Repository
public class UserDaoImpl implements UserDao {
#Autowire
private final RedisTemplate redisTemplate;
public Object fetchUserById(String key) {
return redisTemplate.opsForHash().entries(key);
}
}

Related

Data type is changed when listening message from message queue in RabbitMQ 2.3.6

I am using Spring Rabbit 2.3.6 for my spring application. I have list of Comment entity and send to message queue via this function
public void deletePost(long postId){
Post post = postRepository.findById(postId)
.orElseThrow(() -> new PostNotFoundException(String.valueOf(postId)));
List<Comment> comments = postBase.getComments(post);
postRepository.delete(post);
//post event
Map<String, Object> inputs= new HashMap<>();
inputs.put(InputParam.OBJECT_ID, postId);
inputs.put(InputParam.COMMENTS, comments);
messagingUtil.postEvent(SnwObjectType.POST, SnwActionType.DELETE, inputs);
}
Listening message
#RabbitListener(queues = MessagingConfig.QUEUE)
public void consumeMessageFromQueue(Map<String, Object> inputs) {
}
And this is data I received after listening message. Data type of each element in comment list have been changed, and I can't use it as Comment.
Have you any solution to data type from not being changed?
Updated: Messaging config
#Configuration
public class MessagingConfig {
public static final String QUEUE = "javatechie_queue";
public static final String EXCHANGE = "javatechie_exchange";
public static final String ROUTING_KEY = "javatechie_routingKey";
#Bean
public Queue queue() {
return new Queue(QUEUE);
}
#Bean
public TopicExchange exchange() {
return new TopicExchange(EXCHANGE);
}
#Bean
public Binding binding(Queue queue, TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY);
}
#Bean
public MessageConverter converter() {
return new Jackson2JsonMessageConverter();
}
#Bean
public AmqpTemplate template(ConnectionFactory connectionFactory) {
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(converter());
return rabbitTemplate;
}
}

Spring WebSession Redis Exception

I want to store my WebSession in Redis. There is no problem at put operation, but it throws exception when retrieving stored record. Here is my example stack trace
Caused by:
com.fasterxml.jackson.databind.exc.MismatchedInputException:
Unexpected token (START_OBJECT), expected START_ARRAY: need JSON Array
to contain As.WRAPPER_ARRAY type information for class
java.lang.Object at [Source:
(byte[])"{"attributes":["org.springframework.session.web.server.session.SpringSessionWebSessionStore$SpringSessionMap",{}],"id":"2a5c3d9b-3557-4bd6-bca8-9e221c3a5b41","lastAccessTime":{"nano":800305900,"epochSecond":1605268779},"creationTime":{"nano":800305900,"epochSecond":1605268779},"expired":false,"maxIdleTime":{"seconds":5400,"nano":0,"negative":false,"zero":false,"units":["java.util.ImmutableCollections$List12",[["java.time.temporal.ChronoUnit","SECONDS"],["java.time.temporal.ChronoUnit","NANOS"]]]"[truncated
18 bytes]; line: 1, column: 1]
How could I solve this problem? I don't understand why it is happening? Thanks.
Here is my session service.
#Component
#RequiredArgsConstructor
#Slf4j
public class SessionMappingStorage {
private static final String USR_TO_SESSION___KEY = "USR_SESSION_MAP";
private final ReactiveHashOperations<String, String, Object> hashOps;
public Mono<Boolean> addSession(String username, WebSession session) {
return hashOps.put(USR_TO_SESSION___KEY, username, session);
}
public Mono<WebSession> getSessionByUserId(String username) {
return hashOps.get(USR_TO_SESSION___KEY, username).cast(WebSession.class);
}
}
Here is my redis configuration.
#Bean
public ReactiveRedisTemplate<String, String> reactiveRedisTemplate() {
RedisSerializer keySerializer, hashKeySerializer, hashValueSerializer;
keySerializer = hashKeySerializer = new StringRedisSerializer();
hashValueSerializer = new GenericJackson2JsonRedisSerializer(objectMapper());
RedisSerializationContext.RedisSerializationContextBuilder<String, String> builder =
RedisSerializationContext.newSerializationContext(keySerializer);
RedisSerializationContext<String, String> context =
builder.hashKey(hashKeySerializer).hashValue(hashValueSerializer).build();
return new ReactiveRedisTemplate<>(reactiveRedisConnectionFactory(), context);
}
#Bean
public ReactiveHashOperations<String, String, Object> hashOps() {
return reactiveRedisTemplate().opsForHash();
}
private ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping();
return mapper;
}

Spring data redis returns null on deserializing List type

I am using spring data redis and one of my entity has a list as below.
#RedisHash("person")
#Data
#Builder
public class Person implements Serializable {
#Id
private String name;
private List<Address> addressList;
}
public class Address implements Serializable {
private String postCode;
private String country;
}
The serialisation works fine and the address is stored as
HGETALL person:123456
"name"
"blabla"
"address[0].postCode"
"1111XX"
"address[1].country"
"IN"
but while getting the person back the List is always null ? could someone point out what I am doing wrong here.
My Redis configuration looks as below.
#Configuration
#EnableRedisRepositories
public class RedisConfiguration {
#Bean
public JedisConnectionFactory jedisConnectionFactory() {
return new JedisConnectionFactory();
}
#Bean
public RedisTemplate<String, String> redisTemplate() {
final RedisTemplate<String, String> template = new RedisTemplate<>();
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
mapper.findAndRegisterModules();
template.setKeySerializer(redisSerializer);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.setConnectionFactory(jedisConnectionFactory());
return template;
}
}
I have some suspicion but can you share a bit more code snippet on how you use redisTemplate to save the data into redis?
But most likely its because you set up both Key and Values initialization of RedisTemplate
RedisTemplate<K, V> as <String, String>
Which is why even with Jackson2JsonSerializer it can't serialize and deserialize the List<Address> class properly.
A possible solution would be:
#Bean
public RedisTemplate<String, Person> redisTemplate(JedisConnectionFactory jedisConnectionFactory) {
RedisTemplate<String, Person> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
return redisTemplate;
}
And then you store the whole Person object into Redis
When you need it then you get the whole object out and implement your getter and setter.
Hope this helps

RabbitMQ not serialize message, error convert

I've seen some related questions here, but none worked for me, the rabbit will not serialize my message coming from another application.
Caused by: org.springframework.amqp.AmqpException: No method found for class [B
Below my configuration class to receive the messages.
#Configuration
public class RabbitConfiguration implements RabbitListenerConfigurer{
public final static String EXCHANGE_NAME = "wallet-accounts";
public final static String QUEUE_PAYMENT = "wallet-accounts.payment";
public final static String QUEUE_RECHARGE = "wallet-accounts.recharge";
#Bean
public List<Declarable> ds() {
return queues(QUEUE_PAYMENT, QUEUE_RECHARGE);
}
#Autowired
private ConnectionFactory rabbitConnectionFactory;
#Bean
public AmqpAdmin amqpAdmin() {
return new RabbitAdmin(rabbitConnectionFactory);
}
#Bean
public TopicExchange exchange() {
return new TopicExchange(EXCHANGE_NAME);
}
private List<Declarable> queues(String ... names){
List<Declarable> result = new ArrayList<>();
for (int i = 0; i < names.length; i++) {
result.add(makeQueue(names[i]));
result.add(makeBinding(names[i]));
}
return result;
}
private static Binding makeBinding(String queueName){
return new Binding(queueName, DestinationType.QUEUE, EXCHANGE_NAME, queueName, null);
}
private static Queue makeQueue(String name){
return new Queue(name);
}
#Bean
public MappingJackson2MessageConverter jackson2Converter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
return converter;
}
#Bean
public DefaultMessageHandlerMethodFactory myHandlerMethodFactory() {
DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
factory.setMessageConverter(jackson2Converter());
return factory;
}
#Override
public void configureRabbitListeners(RabbitListenerEndpointRegistrar registrar) {
registrar.setMessageHandlerMethodFactory(myHandlerMethodFactory());
}
}
Using this other configuration, the error is almost the same:
Caused by: org.springframework.amqp.support.converter.MessageConversionException: failed to resolve class name. Class not found [br.com.beblue.wallet.payment.application.accounts.PaymentEntryCommand]
Configuration:
#Configuration
public class RabbitConfiguration {
public final static String EXCHANGE_NAME = "wallet-accounts";
public final static String QUEUE_PAYMENT = "wallet-accounts.payment";
public final static String QUEUE_RECHARGE = "wallet-accounts.recharge";
#Bean
public List<Declarable> ds() {
return queues(QUEUE_PAYMENT, QUEUE_RECHARGE);
}
#Autowired
private ConnectionFactory rabbitConnectionFactory;
#Bean
public AmqpAdmin amqpAdmin() {
return new RabbitAdmin(rabbitConnectionFactory);
}
#Bean
public TopicExchange exchange() {
return new TopicExchange(EXCHANGE_NAME);
}
#Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
private List<Declarable> queues(String ... names){
List<Declarable> result = new ArrayList<>();
for (int i = 0; i < names.length; i++) {
result.add(makeQueue(names[i]));
result.add(makeBinding(names[i]));
}
return result;
}
private static Binding makeBinding(String queueName){
return new Binding(queueName, DestinationType.QUEUE, EXCHANGE_NAME, queueName, null);
}
private static Queue makeQueue(String name){
return new Queue(name);
}
}
Can anyone tell me what's wrong with these settings, or what's missing?
No method found for class [B
Means there is a default SimpleMessageConverter which can't convert your incoming application/json. It is just not aware of that content-type and just falls back to the byte[] to return.
Class not found [br.com.beblue.wallet.payment.application.accounts.PaymentEntryCommand]
Means that Jackson2JsonMessageConverter can't convert your application/json because the incoming __TypeId__ header, representing class of the content, cannot be found in the local classpath.
Well, definitely your configuration for the DefaultMessageHandlerMethodFactory does not make sense for the AMQP conversion. You should consider to use SimpleRabbitListenerContainerFactory bean definition and its setMessageConverter. And yes, consider to inject the proper org.springframework.amqp.support.converter.MessageConverter implementation.
https://docs.spring.io/spring-amqp/docs/1.7.3.RELEASE/reference/html/_reference.html#async-annotation-conversion
From the Spring Boot perspective there is SimpleRabbitListenerContainerFactoryConfigurer to configure on the matter:
https://docs.spring.io/spring-boot/docs/1.5.6.RELEASE/reference/htmlsingle/#boot-features-using-amqp-receiving

How can I configure a Redis instance on Cloudfoundry in slave mode?

I'm trying to configure a master/slave replication on Cloudfoundry but I always fall with a 'ERR unknown command 'SLAVEOF''. I'm using Jedis as the underlying client of spring-data-reids with this code:
#Configuration
#ComponentScan(basePackages = { Constants.REDIS_PACKAGE })
#Order(1)
public class KeyValueConfig {
#Inject
#Named("redisMasterConnectionFactory")
private RedisConnectionFactory redisMasterConnectionFactory;
#Inject
#Named("redisSlaveConnectionFactory")
private RedisConnectionFactory redisSlaveConnectionFactory;
#Inject
#Named("redisCacheConnectionFactory")
private RedisConnectionFactory redisCacheConnectionFactory;
#Bean
public StringRedisTemplate redisMasterTemplate() {
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(
redisMasterConnectionFactory);
HealthChecks.register(new RedisHealthCheck(stringRedisTemplate,
"master"));
return stringRedisTemplate;
}
#Bean
public StringRedisTemplate redisSlaveTemplate() {
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(
redisSlaveConnectionFactory);
HealthChecks
.register(new RedisHealthCheck(stringRedisTemplate, "slave"));
return stringRedisTemplate;
}
#Bean
public StringRedisTemplate redisCacheTemplate() {
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(
redisCacheConnectionFactory);
HealthChecks
.register(new RedisHealthCheck(stringRedisTemplate, "cache"));
return stringRedisTemplate;
}
/**
* Properties to support the local and test mode of operation.
*/
#Configuration
#Profile({ Profiles.LOCAL, Profiles.PROD, Profiles.TEST })
static class Default implements MasterSlaveConfig {
#Inject
private Environment environment;
#Bean
public RedisConnectionFactory redisMasterConnectionFactory() {
JedisConnectionFactory redis = new JedisConnectionFactory();
redis.setHostName(environment.getProperty("redis.master.hostname"));
redis.setPort(environment.getProperty("redis.master.port",
Integer.class));
redis.setPassword(environment.getProperty("redis.master.password"));
redis.setUsePool(true);
return redis;
}
#Bean
public RedisConnectionFactory redisSlaveConnectionFactory() {
JedisConnectionFactory redis = new JedisConnectionFactory();
redis.setHostName(environment.getProperty("redis.slave.hostname"));
redis.setPort(environment.getProperty("redis.slave.port",
Integer.class));
redis.setPassword(environment.getProperty("redis.slave.password"));
redis.setUsePool(true);
return redis;
}
#Bean
public RedisConnectionFactory redisCacheConnectionFactory()
throws Exception {
JedisConnectionFactory redis = new JedisConnectionFactory();
redis.setHostName(environment.getProperty("redis.cache.hostname"));
redis.setPort(environment.getProperty("redis.cache.port",
Integer.class));
redis.setPassword(environment.getProperty("redis.cache.password"));
redis.setUsePool(true);
return redis;
}
}
/**
* Properties to support the cloud mode of operation.
*/
#Configuration
#Profile(Profiles.CLOUDFOUNDRY)
static class Cloud implements MasterSlaveConfig {
#Bean
public RedisConnectionFactory redisMasterConnectionFactory()
throws Exception {
CloudPoolConfiguration cloudPoolConfiguration = new CloudPoolConfiguration();
cloudPoolConfiguration.setPoolSize("3-5");
CloudRedisConnectionFactoryBean factory = new CloudRedisConnectionFactoryBean();
factory.setCloudPoolConfiguration(cloudPoolConfiguration);
factory.setServiceName("redis-master");
factory.afterPropertiesSet();
return factory.getObject();
}
#Bean
public RedisConnectionFactory redisSlaveConnectionFactory()
throws Exception {
CloudPoolConfiguration cloudPoolConfiguration = new CloudPoolConfiguration();
cloudPoolConfiguration.setPoolSize("3-5");
CloudRedisConnectionFactoryBean factory = new CloudRedisConnectionFactoryBean();
factory.setCloudPoolConfiguration(cloudPoolConfiguration);
factory.setServiceName("redis-slave");
factory.afterPropertiesSet();
RedisConnectionFactory redisSlaveConnectionFactory = initSlaveOnMaster(factory);
return redisSlaveConnectionFactory;
}
private RedisConnectionFactory initSlaveOnMaster(
CloudRedisConnectionFactoryBean factory) throws Exception {
RedisConnectionFactory redisSlaveConnectionFactory = factory
.getObject();
RedisServiceInfo serviceInfo = new CloudEnvironment()
.getServiceInfo("redis-master", RedisServiceInfo.class);
Jedis jedis = (Jedis) redisSlaveConnectionFactory.getConnection()
.getNativeConnection();
jedis.slaveof(serviceInfo.getHost(), serviceInfo.getPort());
return redisSlaveConnectionFactory;
}
#Bean
public RedisConnectionFactory redisCacheConnectionFactory()
throws Exception {
CloudPoolConfiguration cloudPoolConfiguration = new CloudPoolConfiguration();
cloudPoolConfiguration.setPoolSize("3-5");
CloudRedisConnectionFactoryBean factory = new CloudRedisConnectionFactoryBean();
factory.setCloudPoolConfiguration(cloudPoolConfiguration);
factory.setServiceName("redis-cache");
factory.afterPropertiesSet();
return factory.getObject();
}
}
interface MasterSlaveConfig {
RedisConnectionFactory redisMasterConnectionFactory() throws Exception;
RedisConnectionFactory redisSlaveConnectionFactory() throws Exception;
RedisConnectionFactory redisCacheConnectionFactory() throws Exception;
}
}
Ok... After checking the code, I found this:
rename-command SLAVEOF "" in redis.conf.erb (https://github.com/cloudfoundry/vcap-services/blob/master/redis/resources/redis.conf.erb)
So the SLAVEOF command is disable on Cloudfoudry, and so:
MONITOR
BGSAVE
BGREWRITEAOF
SLAVEOF
DEBUG
SYNC