Post

2024-08-06-TIL

2024-08-06-TIL

Today I Learned

Redis Error by Version Up for Spring Data Redis

Causes

spring-boot 버전을 2.6.6 -> 3.3.0으로 변경함에 따라 spring-data-redis 의존성도 같이 버전업이 되었다. 여기에서 JPA 엔티티를 직접 Serializable을 구현하게 하고 레디스에 캐싱하는 부분이 있는데, 기존의 Serializer와 새로운 버전의 Serializer가 직렬화하는 방식이 달라서 에러가 발생한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
org.springframework.data.redis.serializer.SerializationException: Cannot deserialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is org.springframework.core.NestedIOException: Failed to deserialize object type; nested exception is java.lang.ClassNotFoundException: org.hibernate.collection.spi.PersistentBag
	at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:84)
	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:571)
	at org.springframework.cache.interceptor.CacheAspectSupport.findCachedItem(CacheAspectSupport.java:536)
	at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:402)
	at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:346)
	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:749)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)
	at com.skplanet.winter.stream.rest.service.CacheService$$EnhancerBySpringCGLIB$$7c52d08b.getTrackByBTrackId_20210311(<generated>)
	at com.skplanet.winter.stream.rest.service.impl.StreamServiceV2Impl.getAudioStream(StreamServiceV2Impl.java:275)
	at com.skplanet.winter.stream.rest.controller.v2.StreamControllerV2.getTrack(StreamControllerV2.java:35)
	at jdk.internal.reflect.GeneratedMethodAccessor114.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at datadog.trace.instrumentation.springweb.HandlerMappingResourceNameFilter.doFilterInternal(HandlerMappingResourceNameFilter.java:50)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is org.springframework.core.NestedIOException: Failed to deserialize object type; nested exception is java.lang.ClassNotFoundException: org.hibernate.collection.spi.PersistentBag
	at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:78)
	at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:36)
	at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:82)
	... 71 more
Caused by: org.springframework.core.NestedIOException: Failed to deserialize object type; nested exception is java.lang.ClassNotFoundException: org.hibernate.collection.spi.PersistentBag
	at org.springframework.core.serializer.DefaultDeserializer.deserialize(DefaultDeserializer.java:75)
	at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:73)
	... 73 more
Caused by: java.lang.ClassNotFoundException: org.hibernate.collection.spi.PersistentBag
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
	at java.base/java.lang.Class.forName0(Native Method)
	at java.base/java.lang.Class.forName(Class.java:467)
	at java.base/java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:778)
	at org.springframework.core.ConfigurableObjectInputStream.resolveClass(ConfigurableObjectInputStream.java:80)
	at java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2045)
	at java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1909)
	at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2235)
	at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1744)
	at java.base/java.io.ObjectInputStream$FieldValues.<init>(ObjectInputStream.java:2617)
	at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2468)
	at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2268)
	at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1744)
	at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:514)
	at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:472)
	at org.springframework.core.serializer.DefaultDeserializer.deserialize(DefaultDeserializer.java:72)
	... 74 more

Fixes

에러의 트레이스의 최상단에는 hibernate 관련 에러가 나와있지만, 근본적으로 레디스에 값을 저장하고 꺼내는 부분에서 발생한 것으로 보임.

ClassNotFoundException: org hibernate.collection.PersistentSet

Redis Serialization Error:

  • https://stackoverflow.com/questions/38695886/cannot-deserialize-nested-exception-is-org-springframework-core-serializer-supp
  • https://stackoverflow.com/questions/35535765/redis-session-serializer-mismatch-between-3-2-and-4-2
  • https://stackoverflow.com/questions/39908279/spring-session-redis-fails-to-deserialize-with-classnotfoundexception
  • https://soobindeveloper8.tistory.com/1018
  • https://github.com/spring-projects/spring-session/issues/1924
  • https://leezzangmin.tistory.com/40
  • https://stackoverflow.com/questions/53204055/caused-by-org-springframework-data-redis-serializer-serializationexception-can
  • https://stackoverflow.com/questions/38153723/java-lang-classnotfoundexception-org-hibernate-collection-internal-persistentba
  • https://stackoverflow.com/questions/39908279/spring-session-redis-fails-to-deserialize-with-classnotfoundexception

Hibernate errors:

  • https://discourse.hibernate.org/t/classnotfoundexception-org-hibernate-collection-persistentset-hibernate-5-4/4590
  • https://developer.jboss.org/thread/199528
  • https://github.com/spring-projects/spring-boot/issues/38959

Serializer:

  • https://stackoverflow.com/questions/72931259/how-to-correctly-use-genericjackson2jsonredisserializer-to-prevent-missing-type
  • https://m.blog.naver.com/cutesboy3/222285071695
  • https://stackoverflow.com/questions/72931259/how-to-correctly-use-genericjackson2jsonredisserializer-to-prevent-missing-type
  • https://velog.io/@hkyo96/Spring-RedisTemplate-Serializer-%EC%84%A4%EC%A0%95
  • https://docs.spring.io/spring-data/data-redis/docs/current/api/org/springframework/data/redis/serializer/JdkSerializationRedisSerializer.html
  • https://velog.io/@hkyo96/Spring-RedisTemplate-Serializer-%EC%84%A4%EC%A0%95
  • https://docs.spring.io/spring-data/redis/docs/current/api/org/springframework/data/redis/serializer/Jackson2JsonRedisSerializer.html

Serializable Isolation Level

  • https://www.postgresql.org/docs/current/transaction-iso.html#:~:text=3.-,Serializable%20Isolation%20Level,%2C%20serially%2C%20rather%20than%20concurrently.
  • https://medium.com/@chanakaanuruddha/serialization-in-java-best-practices-and-strategies-for-protecting-your-data-7fe82a8ea32b
  • https://www.baeldung.com/java-serialization-approaches
  • https://stackoverflow.com/questions/4812011/best-practices-for-sending-serializing-an-object

Spring Cache

  • https://spring.io/guides/gs/caching
  • https://docs.spring.io/spring-boot/reference/io/caching.html
  • https://velog.io/@songs4805/Spring-Cache%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90
  • https://gngsn.tistory.com/157
  • https://www.baeldung.com/spring-cache-tutorial
  • https://conanmoon.medium.com/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EC%9D%BC%EA%B8%B0-spring%EC%97%90%EC%84%9C%EC%9D%98-%EC%BA%90%EC%8B%B1-caching-9221631b4051

Database Session

  • https://stackoverflow.com/questions/10521947/what-is-a-database-session
  • https://www.sciencedirect.com/topics/computer-science/database-session

What Could Possible Go Wrong When I Add a New Field in My DTO?

  • https://medium.com/@malvin.lok/what-could-possible-go-wrong-when-i-add-a-new-field-in-my-dto-48c56a08c01e

JPA Entity Should Implements Serializable?

JPA 엔티티가 Serializable을 구현하도록 해서 외부로의 스펙에서 의존하게 되면 외부로의 API가 영향을 받는다. 따라서 Serializable은 꼭 구현할 필요가 없고 엔티티를 직접 직렬화해서 레디스나 API에서 사용하는 것은 자제하는 것이 좋다.

  • https://velog.io/@jinyeong-afk/Springboot-Entity%EC%97%90-Serializable-%EA%B5%AC%ED%98%84%EC%9D%84-%ED%95%B4%EC%95%BC-%ED%95%98%EB%82%98
  • https://www.inflearn.com/community/questions/17117/serializable-%EC%A7%88%EB%AC%B8-%EB%93%9C%EB%A6%BD%EB%8B%88%EB%8B%A4

Today I Read

  • https://nicholas.carlini.com/writing/2024/how-i-use-ai.html
  • https://medium.com/daangn/%ED%9A%8C%EC%9B%90-%EC%8B%9C%EC%8A%A4%ED%85%9C-msa-%EC%A0%84%ED%99%98-%EB%8F%84%EC%A0%84%EA%B8%B0-mau-1-900%EB%A7%8C-%EB%8B%B9%EA%B7%BC-%EC%9C%A0%EC%A0%80%EB%A5%BC-%EC%9C%84%ED%95%9C-%EC%84%A0%ED%83%9D-43993c582f69
This post is licensed under CC BY 4.0 by the author.