Without this fix the compiled version of elvis
actual behaved differently to the interpreted version
if the value being queried was an empty string. This
is now fixed. It also now correctly handles the
query value being a primitive and addresses the
findings of SPR-15192 where some type inferencing
logic was trying to be too clever, that code has
been deleted.
Issue: SPR-15192
For SPR-14863 we need to adjust the code generation for OpNE
to use !x.equals(y) rather than x!=y. There are also further
cases in the equalityCheck() code in Operator that were not
being handled in the compilation case (when comparators are
used for example). This latter issue also affects OpEQ.
Rather than add yet more bytecode generation, both OpNE and
OpEQ generateCode() methods have been simplified. The
generated code now delegates to equalityCheck() in Operator
which is exactly what the interpreted case does.
This ensures that the compiled code continues to behave just
like the interpreted case. It ensures changes to the interpreted
case are automatically picked up for the compiled case. It
makes the bytecode generation simpler.
The benefit of compilation of SpEL expressions is to avoid
slow reflective calls - that doesn't apply for a basic
(in)equality test so there is no need to go crazy in bytecode
gen.
Issue: SPR-14863
Prior to this commit the SpEL compiler would generate bad bytecode
if the left hand operand of an instanceof was a primitive or
if the right hand operand was a primitive type reference.
With the fixes primitives on the left hand side are now
correctly boxed and special handling is in place for when the
right hand side is a primitive type reference. Using a primitive
type reference on the right always causes the instanceof
check to return false.
Additionally a guard has been added such that compilation is
not allowed when the right hand side of an expression
is not a type reference. If it is, for example, a variable
reference that evaluates to a type reference then that
cannot be expressed in bytecode so compilation is not performed.
Issue: SPR-14250
Prior to this change SpEL did not have an syntactic
construct enabling easy access to a FactoryBean. With this
change it is now possible to use &foo in an expression when
the factory bean should be returned.
Issue: SPR-9511
Before this change the compilation of a method reference or property/field
access was not properly cleaning up the stack if compilation meant
calling a static method or accessing a static field. In these cases there
is no need for a target object on the stack and it should be removed if
present. For a simple expression it is harmless since the end result of
the expression is the thing on the top of the stack, but for nested
expressions if the inner expression suffered this issue, the outer
expression can find itself operating on the wrong element.
The particular issue covered the case of a static field access but this
fix (and associated tests) cover static method, property and field access.
Issue: SPR-13781
When the plus operator is used between strings in a SpEL
expression and that expression is compiled, it is
important to include a cast if computation of any of
the operands isn't obviously leaving strings on the
stack. Likewise if the stack contents are known to
be strings, a cast should not be included.
Issue: SPR-12426
Before this commit the object that #this would refer to in
nested expressions within projection/selection clauses was always
the root context object. This was incorrect as it should be the
element being projected/selected over. This commit introduces
a scope root context object which is set upon entering a new
scope (like when entering a projection or selection). Any
object. With this change this kind of expression now behaves:
where #this is the element of list1. Unqualified references
are also resolved against this scope root context object.
Issues: SPR-10417, SPR-12035, SPR-13055