When calling prototype Beans the first time in a multithreaded manner, the following exception can happen:
Exception in thread "Thread-2" java.lang.ClassCastException: class java.lang.Class cannot be cast to class java.lang.String (java.lang.Class and java.lang.String are in module java.base of loader 'bootstrap')
at org.springframework.beans.factory.support.AbstractBeanDefinition.getBeanClassName(AbstractBeanDefinition.java:393)
at org.springframework.beans.factory.support.AbstractBeanFactory.doResolveBeanClass(AbstractBeanFactory.java:1535)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1502)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:492)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:344)
...
If this happens, the context/runtime will never raise this exception again. So it seems to be an issue only on startup. This seems to happen since Spring Boot 3. There is nothing to find on google. We assume this error to be unknown so far.
To simplify things and for reproduction, we created a repository that can demonstrate the behaviour: Git Demo Repo for this issue
Please elaborate. Thanks in advance
Comment From: wilkinsona
AbstractBeanDefinition
is part of Spring Framework. We'll transfer this issue so that they can investigate.
Comment From: quaff
Reproduced with my local environment.
Comment From: wilkinsona
Thanks for trying it, @quaff. Looking at the code in AbstractBeanDefinition
I can see that getBeanClassName
isn't thread-safe, but I couldn't reproduce it with the sample even after experimenting with different numbers of threads.
@quaff, @mathekcbo, what OS, JVM, and so on did you use and how many iterations were required before the failure occurred?
Comment From: jhoeller
This is a side effect of f64cc08b6210f67924185e65643d600e5bfb968e where we tried to apply instanceof
pattern matching on our new JDK 17 baseline across the codebase, and accidentally lost the defensive access to the beanClass
field that we had in 5.3.x there. I'll restore this for 6.0.11, with pattern matching but on a defensive copy of the field still.
Comment From: mase-ppi
Thanks for trying it, @quaff. Looking at the code in
AbstractBeanDefinition
I can see thatgetBeanClassName
isn't thread-safe, but I couldn't reproduce it with the sample even after experimenting with different numbers of threads.@quaff, @mathekcbo, what OS, JVM, and so on did you use and how many iterations were required before the failure occurred?
OS: Windows and Linux JVM: JDK 17 Temurin Reproduction: It may occur after some seconds (in the shell loop) or after 15 minutes. It differs
Comment From: jhoeller
This should be restored for the upcoming 6.0.11 snapshot now, in sync with the original behavior in the 5.3.x line.
Comment From: mase-ppi
Thank you for this quick response!