Buggy code:
public class Indexer extends SpelNodeImpl { private String cachedReadName ; private Class < ? > cachedReadTargetType ; private PropertyAccessor cachedReadAccessor ; private String cachedWriteName ; private Class < ? > cachedWriteTargetType ; private PropertyAccessor cachedWriteAccessor ; public Indexer ( int pos , SpelNodeImpl expr ) { } @ Override public TypedValue getValueInternal ( ExpressionState state ) throws EvaluationException { TypedValue context = state . getActiveContextObject ( ) ; Object targetObject = context . getValue ( ) ; TypeDescriptor targetObjectTypeDescriptor = context . getTypeDescriptor ( ) ; TypedValue indexValue = null ; Object index = null ; if ( ( targetObject instanceof Map ) && ( ( children [ 0 ] ) instanceof PropertyOrFieldReference ) ) { PropertyOrFieldReference reference = ( ( PropertyOrFieldReference ) ( children [ 0 ] ) ) ; index = reference . getName ( ) ; indexValue = new TypedValue ( index ) ; } else { try { state . pushActiveContextObject ( state . getRootContextObject ( ) ) ; indexValue = children [ 0 ] . getValueInternal ( state ) ; index = indexValue . getValue ( ) ; } finally { state . popActiveContextObject ( ) ; } } <START_BUG> if ( targetObjectTypeDescriptor . isMap ( ) ) { <END_BUG> if ( targetObject == null ) { throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . CANNOT_INDEX_INTO_NULL_VALUE ) ; } Object possiblyConvertedKey = index ; if ( targetObjectTypeDescriptor . isMapEntryTypeKnown ( ) ) { possiblyConvertedKey = state . convertValue ( index , TypeDescriptor . valueOf ( targetObjectTypeDescriptor . getMapKeyType ( ) ) ) ; } Object o = ( ( Map < ? , ? > ) ( targetObject ) ) . get ( possiblyConvertedKey ) ; if ( targetObjectTypeDescriptor . isMapEntryTypeKnown ( ) ) { return new TypedValue ( o , targetObjectTypeDescriptor . getMapValueTypeDescriptor ( ) ) ; } else { return new TypedValue ( o ) ; } } if ( targetObject == null ) { throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . CANNOT_INDEX_INTO_NULL_VALUE ) ; } if ( ( ( targetObject instanceof Collection ) || ( targetObject . getClass ( ) . isArray ( ) ) ) || ( targetObject instanceof String ) ) { int idx = ( ( Integer ) ( state . convertValue ( index , TypeDescriptor . valueOf ( Integer . class ) ) ) ) ; if ( targetObject . getClass ( ) . isArray ( ) ) { return new TypedValue ( accessArrayElement ( targetObject , idx ) , TypeDescriptor . valueOf ( targetObjectTypeDescriptor . getElementType ( ) ) ) ; } else if ( targetObject instanceof Collection ) { Collection c = ( ( Collection ) ( targetObject ) ) ; if ( idx >= ( c . size ( ) ) ) { if ( ! ( growCollection ( state , targetObjectTypeDescriptor . getElementType ( ) , idx , c ) ) ) { throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . COLLECTION_INDEX_OUT_OF_BOUNDS , c . size ( ) , idx ) ; } } int pos = 0 ; for ( Object o : c ) { if ( pos == idx ) { return new TypedValue ( o , TypeDescriptor . valueOf ( targetObjectTypeDescriptor . getElementType ( ) ) ) ; } pos ++ ; } } else if ( targetObject instanceof String ) { String ctxString = ( ( String ) ( targetObject ) ) ; if ( idx >= ( ctxString . length ( ) ) ) { throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . STRING_INDEX_OUT_OF_BOUNDS , ctxString . length ( ) , idx ) ; } return new TypedValue ( String . valueOf ( ctxString . charAt ( idx ) ) ) ; } } if ( ( indexValue . getTypeDescriptor ( ) . getType ( ) ) == ( String . class ) ) { Class < ? > targetObjectRuntimeClass = getObjectClass ( targetObject ) ; String name = ( ( String ) ( indexValue . getValue ( ) ) ) ; EvaluationContext eContext = state . getEvaluationContext ( ) ; try { if ( ( ( ( ( cachedReadName ) != null ) && ( cachedReadName . equals ( name ) ) ) && ( ( cachedReadTargetType ) != null ) ) && ( cachedReadTargetType . equals ( targetObjectRuntimeClass ) ) ) { return cachedReadAccessor . read ( eContext , targetObject , name ) ; } List < PropertyAccessor > accessorsToTry = AstUtils . getPropertyAccessorsToTry ( targetObjectRuntimeClass , state ) ; if ( accessorsToTry != null ) { for ( PropertyAccessor accessor : accessorsToTry ) { if ( accessor . canRead ( eContext , targetObject , name ) ) { if ( accessor instanceof ReflectivePropertyAccessor ) { accessor = ( ( ReflectivePropertyAccessor ) ( accessor ) ) . createOptimalAccessor ( eContext , targetObject , name ) ; } this . cachedReadAccessor = accessor ; this . cachedReadName = name ; this . cachedReadTargetType = targetObjectRuntimeClass ; return accessor . read ( eContext , targetObject , name ) ; } } } } catch ( AccessException e ) { throw new SpelEvaluationException ( getStartPosition ( ) , e , SpelMessage . INDEXING_NOT_SUPPORTED_FOR_TYPE , targetObjectTypeDescriptor . asString ( ) ) ; } } throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . INDEXING_NOT_SUPPORTED_FOR_TYPE , targetObjectTypeDescriptor . asString ( ) ) ; } @ Override public boolean isWritable ( ExpressionState expressionState ) throws SpelEvaluationException { } @ SuppressWarnings ( "unchecked" ) @ Override public void setValue ( ExpressionState state , Object newValue ) throws EvaluationException { } @ SuppressWarnings ( "unchecked" ) private boolean growCollection ( ExpressionState state , Class < ? > elementType , int index , Collection collection ) { } @ Override public String toStringAST ( ) { } private void setArrayElement ( ExpressionState state , Object ctx , int idx , Object newValue , Class clazz ) throws EvaluationException { } private Object accessArrayElement ( Object ctx , int idx ) throws SpelEvaluationException { }

Fix:
if ( targetObject instanceof Map ) {