Our project use springel to evaluate expressions and one strange error happens. It seems like that the first two evaluations are always successful, however when it comes to the third time the evaluation begins to fail. After tracing down the source code we find the reason.
/**
* Compile the expression if it has been evaluated more than the threshold number
* of times to trigger compilation.
* @param expressionState the expression state used to determine compilation mode
*/
private void checkCompile(ExpressionState expressionState) {
this.interpretedCount++;
SpelCompilerMode compilerMode = expressionState.getConfiguration().getCompilerMode();
if (compilerMode != SpelCompilerMode.OFF) {
if (compilerMode == SpelCompilerMode.IMMEDIATE) {
if (this.interpretedCount > 1) {
compileExpression();
}
}
else {
// compilerMode = SpelCompilerMode.MIXED
if (this.interpretedCount > INTERPRETED_COUNT_THRESHOLD) {
compileExpression();
}
}
}
}Each to SpringExpress.getValue() will call this check compile function and when interpretedCount exceeds 1 the compileExpression() is called which explains why evaluation succeeds first two times while fails the third.
The exception looks like this:
Caused by: java.lang.ClassCastException: com.A.bean.User cannot be cast to com.A.bean.User
at spel.Ex3.getValue(Unknown Source) ~[na:na]
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:254) ~[spring-expression-5.0.8.RELEASE.jar:5.0.8.RELEASE]
The exception seems strange com.A.bean.User cannot be cast to com.A.bean.User, an object of a class can't be cast to the class of exactly the same name. So we suspect the root cause is about classLoader.
After some debugging we find that there are two com.A.bean.User class
// ASM BYTECODE FOR "com.A.bean.User" @ClassLoader:org.springframework.boot.devtools.restart.classloader.RestartClassLoader@1aeb256e
// ASM BYTECODE FOR "com.A.bean.User" @ClassLoader:sun.misc.Launcher$AppClassLoader@18b4aac2And the RestartClassLoader is because of our usage of spring-boot-devtools which is used for hot deploy.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>AxonFramework/AxonFramework#344 https://stackoverflow.com/questions/31282985/classcastexception-on-custom-class-loading