title: Springboot caching SerializationException using Redis
body: <p>I'm trying to make a springboot Redis caching demo. </p>
  
  <p>Here is the Redis configuration class:</p>
  
  <pre><code>@Configuration
  @EnableCaching
  public class RedisConfig extends CachingConfigurerSupport {
  
      @Value("${custom.config.redis.ttl}")
      private Integer timeTtl;
  
      @Bean
      public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
          return new RedisCacheManager(
                  RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),
                  this.getRedisCacheConfigurationWithTtl(timeTtl),
                  this.getRedisCacheConfigurationMap()
          );
      }
  
      private Map&lt;String, RedisCacheConfiguration&gt; getRedisCacheConfigurationMap() {
          Map&lt;String, RedisCacheConfiguration&gt; redisCacheConfigurationMap = new HashMap&lt;&gt;(10);
          redisCacheConfigurationMap
                  .put("SsoCache", this.getRedisCacheConfigurationWithTtl(24 * 60 * 60));
          redisCacheConfigurationMap
                  .put("BasicDataCache", this.getRedisCacheConfigurationWithTtl(30 * 60));
          return redisCacheConfigurationMap;
      }
  
      private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {
          Jackson2JsonRedisSerializer&lt;Object&gt; jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer&lt;&gt;(
                  Object.class);
          ObjectMapper om = new ObjectMapper();
          om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
          om.activateDefaultTyping(BasicPolymorphicTypeValidator.builder().build(),
                  ObjectMapper.DefaultTyping.NON_FINAL);
          jackson2JsonRedisSerializer.setObjectMapper(om);
          RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration
                  .defaultCacheConfig();
          redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(
                  RedisSerializationContext
                          .SerializationPair
                          .fromSerializer(jackson2JsonRedisSerializer)
          ).entryTtl(Duration.ofSeconds(seconds));
  
          return redisCacheConfiguration;
      }
  }
  </code></pre>
  
  <p>redis service:</p>
  
  <pre><code>@Service
  @Slf4j
  public class RedisService {
  
      private final StringRedisTemplate redisTemplate;
  
      public RedisService(StringRedisTemplate redisTemplate) {
          Assert.notNull(redisTemplate, "redisTemplate is required");
          this.redisTemplate = redisTemplate;
      }
  
      @Cacheable(value = "user", key = "#userRedis.getId()")
      public UserRedis saveUser(UserRedis userRedis) {
          log.trace("user{} is saved", userRedis);
          return userRedis;
      }
  }
  </code></pre>
  
  <p>test class:</p>
  
  <pre><code>    @SpringBootTest
      class RedisServiceTest {
  
          @Autowired
          private RedisService redisService;
  
          @Autowired
          private StringRedisTemplate stringRedisTemplate;
  
          @Autowired
          private RedisTemplate redisTemplate;
  
          @Test
          void saveUser() {
              UserRedis japhy = UserRedis.builder().id(3L).name("japhy").age(10L).build();
              UserRedis userRedis = redisService.saveUser(japhy);
              Assertions.assertThat(userRedis).isNotNull();
              Assertions.assertThat(userRedis.getId()).isEqualTo(3L);
              Assertions.assertThat(userRedis.getName()).isEqualTo("japhy");
              Assertions.assertThat(userRedis.getAge()).isEqualTo(10L);
          }
      }
  </code></pre>
  
  <p>model class:</p>
  
  <pre><code>    @Builder
      public class UserRedis implements Serializable {
  
          private static final long serialVersionUID = -1541408164202572383L;
          private Long id;
  
          private String name;
  
          private Long age;
  
          public UserRedis() {
          }
  
          public UserRedis(Long id, String name, Long age) {
              this.id = id;
              this.name = name;
              this.age = age;
          }
  
          public Long getId() {
              return id;
          }
  
          public void setId(Long id) {
              this.id = id;
          }
  
          public String getName() {
              return name;
          }
  
          public void setName(String name) {
              this.name = name;
          }
  
          public Long getAge() {
              return age;
          }
  
          public void setAge(Long age) {
              this.age = age;
          }
      }
  </code></pre>
  
  <p>application.yml:</p>
  
  <pre><code>spring:
    redis:
      database: 0
      # Redis服务器地址
      host: 39.99.155.113
      # Redis服务器连接端口
      port: 6379
      # Redis服务器连接密码（默认为空）
      password:
      lettuce:
        pool:
          max-active: 8
          max-wait: -1s
          max-idle: 8
          min-idle: 0
    cache:
      redis:
        time-to-live: 180s #缓存超时时间ms
        cache-null-values: false #是否缓存空值
      type: redis
  
  custom:
    config:
      redis:
        ttl: 1800
  </code></pre>
  
  <p>I can save the modal class to Redis successfully. But when I try to read it from Redis. It throws an exception:</p>
  
  <pre><code>org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Could not resolve type id 'com.japhy.examples.model.UserRedis' as a subtype of `java.lang.Object`: Configured `PolymorphicTypeValidator` (of type `com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator`) denied resolution
   at [Source: (byte[])"["com.japhy.examples.model.UserRedis",{"id":3,"name":"japhy","age":10}]"; line: 1, column: 39]; nested exception is com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'com.japhy.examples.model.UserRedis' as a subtype of `java.lang.Object`: Configured `PolymorphicTypeValidator` (of type `com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator`) denied resolution
   at [Source: (byte[])"["com.japhy.examples.model.UserRedis",{"id":3,"name":"japhy","age":10}]"; line: 1, column: 39]
  
      at org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer.deserialize(Jackson2JsonRedisSerializer.java:75)
      at org.springframework.data.redis.serializer.DefaultRedisElementReader.read(DefaultRedisElementReader.java:48)
      at org.springframework.data.redis.serializer.RedisSerializationContext$SerializationPair.read(RedisSerializationContext.java:272)
      at org.springframework.data.redis.cache.RedisCache.deserializeCacheValue(RedisCache.java:260)
      at org.springframework.data.redis.cache.RedisCache.lookup(RedisCache.java:94)
      at org.springframework.cache.support.AbstractValueAdaptingCache.get(AbstractValueAdaptingCache.java:58)
      at org.springframework.cache.interceptor.AbstractCacheInvoker.doGet(AbstractCacheInvoker.java:73)
      at org.springframework.cache.interceptor.CacheAspectSupport.findInCaches(CacheAspectSupport.java:554)
      at org.springframework.cache.interceptor.CacheAspectSupport.findCachedItem(CacheAspectSupport.java:519)
      at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:401)
      at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:345)
      at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
      at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
      at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
      at com.japhy.examples.RedisService$$EnhancerBySpringCGLIB$$e0f4e77a.saveUser(&lt;generated&gt;)
      at com.japhy.examples.RedisServiceTest.saveUser(RedisServiceTest.java:32)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:675)
      at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
      at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:125)
      at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:132)
      at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:124)
      at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:74)
      at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
      at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
      at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:104)
      at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:62)
      at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:43)
      at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:35)
      at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
      at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
      at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:202)
      at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
      at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:198)
      at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
      at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
      at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
      at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
      at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
      at java.util.ArrayList.forEach(ArrayList.java:1249)
      at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
      at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
      at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
      at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
      at java.util.ArrayList.forEach(ArrayList.java:1249)
      at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
      at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
      at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
      at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
      at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
      at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
      at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
      at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
      at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
      at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
      at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
      at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
      at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
      at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69)
      at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
      at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
      at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
  Caused by: com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'com.japhy.examples.model.UserRedis' as a subtype of `java.lang.Object`: Configured `PolymorphicTypeValidator` (of type `com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator`) denied resolution
   at [Source: (byte[])"["com.japhy.examples.model.UserRedis",{"id":3,"name":"japhy","age":10}]"; line: 1, column: 39]
      at com.fasterxml.jackson.databind.exc.InvalidTypeIdException.from(InvalidTypeIdException.java:43)
      at com.fasterxml.jackson.databind.DeserializationContext.invalidTypeIdException(DeserializationContext.java:1758)
      at com.fasterxml.jackson.databind.DatabindContext._throwSubtypeClassNotAllowed(DatabindContext.java:291)
      at com.fasterxml.jackson.databind.DatabindContext.resolveAndValidateSubType(DatabindContext.java:248)
      at com.fasterxml.jackson.databind.jsontype.impl.ClassNameIdResolver._typeFromId(ClassNameIdResolver.java:72)
      at com.fasterxml.jackson.databind.jsontype.impl.ClassNameIdResolver.typeFromId(ClassNameIdResolver.java:66)
      at com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase._findDeserializer(TypeDeserializerBase.java:156)
      at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._deserialize(AsArrayTypeDeserializer.java:97)
      at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer.deserializeTypedFromAny(AsArrayTypeDeserializer.java:71)
      at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer$Vanilla.deserializeWithType(UntypedObjectDeserializer.java:712)
      at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:68)
      at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4202)
      at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3309)
      at org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer.deserialize(Jackson2JsonRedisSerializer.java:73)
      ... 79 more
  
  </code></pre>
  
  <p>I have read the Spring document in <a href="https://docs.spring.io/spring-data/data-redis/docs/current/reference/html/#redis:serializer" rel="nofollow noreferrer">https://docs.spring.io/spring-data/data-redis/docs/current/reference/html/#redis:serializer</a>. But still have no idea how to fix the problem.
  Any advice? thanks!</p>