1.问题:使用@cacheable注解报错信息如下,很明显是jackson序列化时出的错误
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_ARRAY token[["com.xxx.xxx.xxxxxxx.response.SummaryLeftResponse",{"mainpName":null,"mainpType":null,"mainpValue":2,"mainpUnit":"PERCENT","vsType":"BULB","vsValue":null,"vsFlag":-1,"vsLeft":-2.5,"vsLeftFlag":-1,"vsLeftUnit":"PERCENT","vsRight":-6.5,"vsRightFlag":-1,"vsRightUnit":"PERCENT","tableTimeRatio":16.0,"tableCompletedRatio":2.7,"rightAry":"101,3785"}]]]"; line: 1, column: 365] (through reference chain: java.util.ArrayList[0]->com.xxx.xxx.xxxxxxx.response.SummaryLeftResponse["rightAry"])
2.导致问题是SummaryLeftResponse对象里有一个rightAry字段是string类型的,接收到的数据是123,212这样的,所以导致在使用@cacheable序列化错误
我的redisManager配置
// 分别创建String和JSON格式序列化对象,对缓存数据key和value进行转换 , RedisSerializer<String> strSerializer = new StringRedisSerializer(); // 解决查询缓存转换异常的问题 Jackson2JsonRedisSerializer jacksonSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jacksonSerializer.setObjectMapper(om); // String cacheKey = commonConfigService.getValueByKey("cache_key"); // 定制缓存数据序列化方式以及时效 final org.springframework.data.redis.cache.RedisCacheConfiguration redisCacheConfiguration = org.springframework.data.redis.cache.RedisCacheConfiguration.defaultCacheConfig() .computePrefixWith(cacheName -> cacheKey) .entryTtl(Duration.ofHours(12)) .serializeKeysWith(RedisSerializationContext.SerializationPair .fromSerializer(strSerializer)) .serializeValuesWith(RedisSerializationContext.SerializationPair .fromSerializer(jacksonSerializer)) .disableCachingNullValues(); final RedisCacheManager cacheManager = RedisCacheManager.builder(connectionFactory) .cacheDefaults(redisCacheConfiguration) .build(); return cacheManager;
3.当我弃用Jackson2JsonRedisSerializer使用JDKJsonRedisSerializer时发现每个对象都要去实现一次Serializable感觉对象一多就很麻烦,还是放弃了,打算使用FastJson2JsonRedisSerialize试试,我的代码
package com.sgm.cadillac.common.config; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.parser.ParserConfig; import com.alibaba.fastjson.serializer.SerializerFeature; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.SerializationException; import java.nio.charset.Charset; public class FastJson2JsonRedisSerialize<T> implements RedisSerializer<T> { public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); private Class<T> clazz; /** * 设置白名单---非常重要******** 使用fastjson的时候:序列化时将class信息写入,反解析的时候, fastjson默认情况下会开启autoType的检查,相当于一个白名单检查, 如果序列化信息中的类路径不在autoType中, 反解析就会报com.alibaba.fastjson.JSONException: autoType is not support的异常 可参考 https://blog.csdn.net/u012240455/article/details/80538540 */ static { ParserConfig.getGlobalInstance().setAutoTypeSupport(true); // ParserConfig.getGlobalInstance().addAccept("com.sgm.cadillac.cockpit.response"); } public FastJson2JsonRedisSerialize(Class clazz) { super(); this.clazz = clazz; } /** * 序列化 * * @param t * @return * @throws SerializationException */ @Override public byte[] serialize(T t) throws SerializationException { if (t == null) { return new byte[0]; } try { return JSON.toJSONBytes(t, SerializerFeature.WriteClassName); } catch (Exception ex) { throw new SerializationException("Could not write JSON: " + ex.getMessage(), ex); } } /** * 反序列化 * * @param bytes * @return * @throws SerializationException */ @Override public T deserialize(byte[] bytes) throws SerializationException { if (null == bytes || bytes.length <= 0) { return null; } String str = new String(bytes, DEFAULT_CHARSET); T t = JSON.parseObject(str, clazz); return t; } }
===============================================================
@Bean public RedisSerializer fastJson2JsonRedisSerialize() { return new FastJson2JsonRedisSerialize<>(Object.class); }
@Bean public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) { // 分别创建String和JSON格式序列化对象,对缓存数据key和value进行转换 , RedisSerializer<String> strSerializer = new StringRedisSerializer(); //序列化方式2 FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);//JSONObject // String cacheKey = commonConfigService.getValueByKey("cache_key"); RedisSerializationContext.SerializationPair<String> serializerKey = RedisSerializationContext.SerializationPair .fromSerializer(strSerializer); RedisSerializationContext.SerializationPair<Object> serializerValue = RedisSerializationContext. SerializationPair.fromSerializer(new FastJson2JsonRedisSerialize<>(Object.class)); // SerializationPair.fromSerializer(fastJsonRedisSerializer); org.springframework.data.redis.cache.RedisCacheConfiguration defaultCacheConfig = org.springframework.data.redis.cache.RedisCacheConfiguration.defaultCacheConfig(); defaultCacheConfig = defaultCacheConfig .computePrefixWith(cacheName -> cacheKey) .entryTtl(Duration.ofSeconds(100)) .serializeKeysWith(serializerKey) .serializeValuesWith(serializerValue) .disableCachingNullValues(); //初始化RedisCacheManager return new RedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory), defaultCacheConfig); }
4.使用了FastJson2JsonRedisSerialize序列化后还是出现问题,在我使用@Cacheable后
,发现反序列化的数据变成这样的,多了一个字符串数值,其实正确的是只有一组数组,这样很奇怪,为什么会出现这种问题呢?
5.临时处理,在反序列化重写方法里只取正确的那一条记录即可解决,治标不治本吧,希望知道具体原因的小伙伴留言帮忙解答下,或者提出更好的使用FastJson2JsonRedisSerialize处理方式