【问题标题】:Jedis SpringBoot cannot serialize and deserialize Map<String, Object>Jedis SpringBoot 无法序列化和反序列化 Map<String, Object>
【发布时间】:2023-04-07 10:54:02
【问题描述】:

将@Cacheable 注释添加到我的一种休息方法后出现以下错误:

"status": 500,
"error": "Internal Server Error",
"message": "class java.util.ArrayList cannot be cast to class java.util.Map (java.util.ArrayList and java.util.Map are in module java.base of loader 'bootstrap')",

方法声明为:

@Cacheable("loadDevicesFloors")
@GetMapping("/floors/all-devices")
public Map<String, DevicesFloorDTO> loadDevicesFloors() {...

DeviceFloorDTO 如下所示:

public class DevicesFloorDTO implements Serializable {
    private final List<DeviceDTO> deviceDTOs;
    private final String floorName;
    private final Integer floorIndex;
    public DevicesFloorDTO(List<DeviceDTO> devicesDtos, String floorName, Integer floorIndex) {
        this.deviceDTOs = devicesDtos;
        this.floorName = floorName;
        this.floorIndex = floorIndex;
    }...

另外我的@Bean redisTemplate 方法实现:

@Bean
    JedisConnectionFactory jedisConnectionFactory() {
        JedisConnectionFactory jedisConFactory
                = new JedisConnectionFactory();
        jedisConFactory.setHostName(redisHost);
        jedisConFactory.setPort(redisPort);
        jedisConFactory.setPassword(redisPassword);
        return jedisConFactory;
    }

@Bean
    public RedisTemplate<?, ?> redisTemplate() {
        RedisTemplate<byte[], byte[]> template = new RedisTemplate<>();
        template.setConnectionFactory(jedisConnectionFactory());
        return template;
    }

有人知道这个实现有什么问题吗?如果没有@Cacheable,它会按预期工作,但是在添加@Cacheable 之后会发生错误。我搜索了很多,但仍然不知道导致此错误的原因以及如何解决此问题。任何评论都可能会有所帮助。非常感谢!

【问题讨论】:

  • 你能用这个命令从redis中取出值吗:redis-cli GET '&lt;key&gt;'

标签: java spring-boot serialization redis jedis


【解决方案1】:

在序列化/反序列化期间,您为 Map Map&lt;String, DevicesFloorDTO&gt; 指定的泛型在运行时将不可用。你想在 Reids 中以什么格式保存你的对象?他们是保存为 JSON(字符串)还是二进制文件?

我们在GenericJackson2JsonRedisSerializer 方面取得了成功,因为它将类信息保存在 JSON 字符串中,因此 Redis 确切地知道如何重新创建对象。

还有一些情况需要 Wrapper Object 才能正确序列化/反序列化对象。


    @Bean
    public RedisCacheManager cacheManager( RedisConnectionFactory redisConnectionFactory,
                                           ResourceLoader resourceLoader ) {
        RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager
                .builder( redisConnectionFactory )
                .cacheDefaults( determineConfiguration() );
        List<String> cacheNames = this.cacheProperties.getCacheNames();
        if ( !cacheNames.isEmpty() ) {
            builder.initialCacheNames( new LinkedHashSet<>( cacheNames ) );
        }
        return builder.build();
    }

    private RedisCacheConfiguration determineConfiguration() {
        if ( this.redisCacheConfiguration != null ) {
            return this.redisCacheConfiguration;
        }
        CacheProperties.Redis redisProperties = this.cacheProperties.getRedis();
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();

        ObjectMapper mapper = new Jackson2ObjectMapperBuilder()
                .modulesToInstall( new SimpleModule().addSerializer( new NullValueSerializer( null ) ) )
                .failOnEmptyBeans( false )
                .build();
        mapper.enableDefaultTyping( ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY );

        GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer( mapper );

        //get the mapper b/c they registered some internal modules
        config = config.serializeValuesWith( RedisSerializationContext.SerializationPair.fromSerializer( serializer ) );

        if ( redisProperties.getTimeToLive() != null ) {
            config = config.entryTtl( redisProperties.getTimeToLive() );
        }
        if ( redisProperties.getKeyPrefix() != null ) {
            config = config.prefixKeysWith( redisProperties.getKeyPrefix() );
        }
        if ( !redisProperties.isCacheNullValues() ) {
            config = config.disableCachingNullValues();
        }
        if ( !redisProperties.isUseKeyPrefix() ) {
            config = config.disableKeyPrefix();
            config = config.computePrefixWith( cacheName -> cacheName + "::" );
        }
        return config;
    }

【讨论】:

  • Chris Savory 您的回答恰到好处。有用!非常感谢!你为我节省了很多时间!
猜你喜欢
  • 2014-05-19
  • 1970-01-01
  • 1970-01-01
  • 2012-12-25
  • 2014-10-16
  • 2013-12-29
  • 2018-08-24
  • 2018-09-10
  • 1970-01-01
相关资源
最近更新 更多