Skip to content

Fix compilation of SpEL Elvis with primitive operands - #37575

Open
CCCLL wants to merge 1 commit into
spring-projects:mainfrom
CCCLL:fix/spel-elvis-primitive-compilation
Open

CCCLL wants to merge 1 commit into
spring-projects:mainfrom
CCCLL:fix/spel-elvis-primitive-compilation

Conversation

@CCCLL

@CCCLL CCCLL commented Oct 23, 2026

Copy link
Copy Markdown

Compiling a SpEL Elvis expression whose operands have the same primitive
type, such as count ?: 0 for an int property or 3.5d ?: 4.5d,
fails with a VerifyError ("Failed to instantiate CompiledExpression").
In IMMEDIATE compiler mode, every evaluation after the first one
throws, while MIXED mode falls back to interpreted mode.

SpelParserConfiguration configuration = SpelParserConfiguration.builder()
		.compilerMode(SpelCompilerMode.IMMEDIATE).build();
Expression expression = new SpelExpressionParser(configuration).parseExpression("length() ?: 0");
expression.getValue("abc");  // 3
expression.getValue("abc");  // SpelEvaluationException: EL1074E (3 with this change)

Elvis.generateCode() boxes the left-hand value for the null check, but
it does not box the right-hand value when the exit type descriptor is
primitive (which is the case when both operands have the same primitive
type), so the two branches leave different types on the stack. Operands
of different types, such as 3 ?: 'foo', are not affected since both
values are boxed.

A primitive value is neither null nor an empty String, so in that
case this change only generates the code for the left-hand operand,
boxing its value if the exit type descriptor is not primitive. The
else branch that boxed the left-hand value is no longer needed, and a
void left-hand operand keeps its current behavior.

The new test covers int, long, double and boolean literals as
well as a method returning int; it fails without the change and passes
with it. ./gradlew :spring-expression:check passes on JDK 25.

7.0.x is affected as well: the left-hand value has been boxed for the
null check since gh-19758, but the right-hand value of an Elvis
expression with a primitive exit type never was.

Prior to this commit, compiling a SpEL Elvis expression whose operands
have the same primitive type, such as `count ?: 0` for an int property
or `3.5d ?: 4.5d`, failed with a VerifyError, reported as "Failed to
instantiate CompiledExpression". In IMMEDIATE compiler mode, every
evaluation after the first one therefore failed, whereas MIXED mode
fell back to interpreted mode.

The generated code boxed the left-hand value for the null check but did
not box the right-hand value, since the exit type descriptor was
primitive, so the two branches left different types on the stack.

Since a primitive value is neither null nor an empty String, this
commit only generates the code for the left-hand operand in that case,
boxing its value if the exit type descriptor is not primitive.

Signed-off-by: Jialin Chen <cccll2019@gmail.com>
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Oct 23, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: waiting-for-triage An issue we've not yet triaged or decided on

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants