Bin Hawking opened SPR-15893 and commented

given variable = 9, I expect: map[variable] = map[9]

but in the current SpEL implementation:

map[variable]
= map[ (variable) ] = map[ ((((variable)))) ]   // weird
= map['variable']

After reading the code, I found the cause in org.springframework.expression.spel.ast.Indexer::getValueRef().

// This first part of the if clause prevents a 'double dereference' of
// the property (#10516)
if (targetObject instanceof Map && (this.children[0] instanceof PropertyOrFieldReference)) {
...
}
else ...

10516 was for SpEL 3.x; while, as far as I can see from the 4.3.x code, dot property has nothing to do with Indexer. An Indexer node is instantiated only after eating [. Hence the fix of #10516 should NOT be in Indexer.

In practice, I used my revision of spring-expression in which removed are those lines cited above. Then I got map[variable]=map[9] in my app and the other parts still function correctly.

I hope it can be the official behavior of SpEL.


Affects: 4.3.10, 5.0 RC3

Issue Links:

  • 10516

Comment From: spring-projects-issues

Bin Hawking commented

Indexer::generateCode(...) is also impacted:

    else if (this.indexedType == IndexedType.MAP) {
         mv.visitTypeInsn(CHECKCAST, "java/util/Map");
         // Special case when the key is an unquoted string literal that will be parsed as
         // a property/field reference
         if ((this.children[0] instanceof PropertyOrFieldReference)) {
              PropertyOrFieldReference reference = (PropertyOrFieldReference) this.children[0];
              String mapKeyName = reference.getName();
              mv.visitLdcInsn(mapKeyName);
         }
         else  ......

Comment From: sbrannen

Apologies for getting to this issue so many years later!

If the key supplied to a map is an unquoted string literal, the key will be parsed as a property or field reference.

If var is a SpEL variable assigned the value of 9, then to access map[9] using the variable you would need to use the # syntax to reference the variable as in map[#var].

In light of that, I am closing this issue as "works as designed".