sixhours-team / memcached-spring-boot

Library that provides support for auto-configuration of Memcached cache in a Spring Boot application.
Apache License 2.0
71 stars 33 forks source link

Confusing ClassCastException #127

Closed Mr-LiuDC closed 3 years ago

Mr-LiuDC commented 3 years ago

1. Confusing ClassCastException

I have added dependency:

<dependency>
    <groupId>io.sixhours</groupId>
    <artifactId>memcached-spring-boot-starter</artifactId>
    <version>2.4.0</version>
</dependency>

Here is my java code:

@Override
@CachePut(key = "#memcachedDemo.id")
public MemcachedDemo create(MemcachedDemo memcachedDemo) {
    MemcachedDemo demo = MemcachedDemo.create(memcachedDemo);
    return repository.save(demo);
}

@Override
@Cacheable(key = "#id")
public MemcachedDemo findById(String id) {
    return repository.findById(id).orElse(null);
}

The create method works well, but findById method throw this exception:

java.lang.ClassCastException: fun.aipark.dao.domain.MemcachedDemo cannot be cast to fun.aipark.dao.domain.MemcachedDemo

The cache object is the same class.

@Data
@Entity
public class MemcachedDemo implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    private String id;

    private String name;

    private String description;

    private Date createTime;

    private Date lastModifiedTime;

    public static MemcachedDemo create(MemcachedDemo memcachedDemo) {
        MemcachedDemo demo = new MemcachedDemo();
        Date date = new Date();
        BeanUtils.copyProperties(memcachedDemo, demo);
        demo.createTime = date;
        demo.lastModifiedTime = date;
        return demo;
    }

    public void modified(MemcachedDemo memcachedDemo) {
        BeanUtils.copyProperties(memcachedDemo, this, "id", "createTime", "lastModifiedTime");
        this.lastModifiedTime = new Date();
    }
}

2. AutoConfiguration seems not working in version 2.4.1

<dependency>
    <groupId>io.sixhours</groupId>
    <artifactId>memcached-spring-boot-starter</artifactId>
    <version>2.4.1</version>
</dependency>
java.lang.IllegalStateException: Cannot load configuration class: io.sixhours.memcached.cache.XMemcachedCacheAutoConfiguration
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.enhanceConfigurationClasses(ConfigurationClassPostProcessor.java:413) ~[spring-context-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanFactory(ConfigurationClassPostProcessor.java:253) ~[spring-context-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:286) ~[spring-context-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:130) ~[spring-context-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:706) ~[spring-context-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:532) ~[spring-context-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) ~[spring-boot-2.1.18.RELEASE.jar:2.1.18.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:744) [spring-boot-2.1.18.RELEASE.jar:2.1.18.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:391) [spring-boot-2.1.18.RELEASE.jar:2.1.18.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) [spring-boot-2.1.18.RELEASE.jar:2.1.18.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) [spring-boot-2.1.18.RELEASE.jar:2.1.18.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1204) [spring-boot-2.1.18.RELEASE.jar:2.1.18.RELEASE]
    at fun.aipark.SpringbootCacheMemcachedApp.main(SpringbootCacheMemcachedApp.java:15) [classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_291]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_291]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_291]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_291]
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-2.1.18.RELEASE.jar:2.1.18.RELEASE]
Caused by: java.lang.IllegalArgumentException: No visible constructors in class io.sixhours.memcached.cache.XMemcachedCacheAutoConfiguration
    at org.springframework.cglib.proxy.Enhancer.filterConstructors(Enhancer.java:763) ~[spring-core-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:662) ~[spring-core-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.cglib.transform.TransformingClassGenerator.generateClass(TransformingClassGenerator.java:33) ~[spring-core-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25) ~[spring-core-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanFactoryAwareGeneratorStrategy.generate(ConfigurationClassEnhancer.java:252) ~[spring-context-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:358) ~[spring-core-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:585) ~[spring-core-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:110) ~[spring-core-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:108) ~[spring-core-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54) ~[spring-core-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) ~[na:1.8.0_291]
    at java.util.concurrent.FutureTask.run(FutureTask.java) ~[na:1.8.0_291]
    at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61) ~[spring-core-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34) ~[spring-core-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:134) ~[spring-core-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:319) ~[spring-core-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:572) ~[spring-core-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:419) ~[spring-core-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassEnhancer.createClass(ConfigurationClassEnhancer.java:137) ~[spring-context-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassEnhancer.enhance(ConfigurationClassEnhancer.java:109) ~[spring-context-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.enhanceConfigurationClasses(ConfigurationClassPostProcessor.java:402) ~[spring-context-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    ... 17 common frames omitted
igorbolic commented 3 years ago

Could you add the full stack trace for the first error (cast exception) and open a separate issue for the cache auto-configuration issue.

In case you are using the Spring Boot, could you please specify the version you are using.

Mr-LiuDC commented 3 years ago

@igorbolic Here is the full stack trace.

First create, then findById

Hibernate: select memcachedd0_.id as id1_0_0_, memcachedd0_.create_time as create_t2_0_0_, memcachedd0_.description as descript3_0_0_, memcachedd0_.last_modified_time as last_mod4_0_0_, memcachedd0_.name as name5_0_0_ from memcached_demo memcachedd0_ where memcachedd0_.id=?
Hibernate: insert into memcached_demo (create_time, description, last_modified_time, name, id) values (?, ?, ?, ?, ?)
2021-09-10 22:44:54.662 ERROR 13036 --- [nio-8080-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.ClassCastException: fun.aipark.dao.domain.MemcachedDemo cannot be cast to fun.aipark.dao.domain.MemcachedDemo] with root cause

java.lang.ClassCastException: fun.aipark.dao.domain.MemcachedDemo cannot be cast to fun.aipark.dao.domain.MemcachedDemo
    at fun.aipark.service.impl.MemcachedDemoServiceImpl$$EnhancerBySpringCGLIB$$92379760.findById(<generated>) ~[classes/:na]
    at fun.aipark.controller.MemcachedDemoController.findById(MemcachedDemoController.java:45) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_291]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_291]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_291]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_291]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105) ~[spring-webmvc-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) ~[spring-webmvc-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:626) ~[tomcat-embed-core-9.0.39.jar:4.0.FR]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:733) ~[tomcat-embed-core-9.0.39.jar:4.0.FR]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.39.jar:9.0.39]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:94) ~[spring-web-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.1.19.RELEASE.jar:5.1.19.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) [tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) [tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) [tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) [tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374) [tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590) [tomcat-embed-core-9.0.39.jar:9.0.39]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.39.jar:9.0.39]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_291]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_291]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.39.jar:9.0.39]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_291]
Mr-LiuDC commented 3 years ago

This really puzzles me. When I run this maven module as a standalone project, the exception disappears.

But exception occurs when I run this project as a maven submodule. I can be sure that there is no second class named MemcachedDemo and I have executed mvnw clean.

igorbolic commented 3 years ago

Indeed it's a strange exception and difficult to reproduce.

My guess is the issue might be caused if you have a different class version (serialization ID) serialized within cache and you're trying to read it in the application. Maybe invalidating the cache, and try create / find again might solve it.

One more thing that might cause the issue is if different class loader is used when reading from the cache. Since the library is built on top of Spring Cache abstraction I don't believe there is something we can do to resolve it, perhaps you could post your issue on Stack Overflow.

Mr-LiuDC commented 3 years ago

@igorbolic

Thanks anyway.

A high probability is that this issue might caused by different class loaders.