@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
/ *
* Copyright 2002 - 2017 the original author or authors .
* Copyright 2002 - 2018 the original author or authors .
*
* Licensed under the Apache License , Version 2 . 0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
@ -103,21 +103,20 @@ public class Indexer extends SpelNodeImpl {
@@ -103,21 +103,20 @@ public class Indexer extends SpelNodeImpl {
@Override
protected ValueRef getValueRef ( ExpressionState state ) throws EvaluationException {
TypedValue context = state . getActiveContextObject ( ) ;
Object targetObject = context . getValue ( ) ;
Object target = context . getValue ( ) ;
TypeDescriptor targetDescriptor = context . getTypeDescriptor ( ) ;
TypedValue indexValue = null ;
Object index = null ;
TypedValue indexValue ;
Object index ;
// This first part of the if clause prevents a 'double dereference' of
// the property (SPR-5847)
if ( targetObject instanceof Map & & ( this . children [ 0 ] instanceof PropertyOrFieldReference ) ) {
// This first part of the if clause prevents a 'double dereference' of the property (SPR-5847)
if ( target instanceof Map & & ( this . children [ 0 ] instanceof PropertyOrFieldReference ) ) {
PropertyOrFieldReference reference = ( PropertyOrFieldReference ) this . children [ 0 ] ;
index = reference . getName ( ) ;
indexValue = new TypedValue ( index ) ;
}
else {
// In case the map key is unqualified, we want it evaluated against
// the root object so temporarily push that on whilst evaluating the key
// In case the map key is unqualified, we want it evaluated against the root object
// so temporarily push that on whilst evaluating the key
try {
state . pushActiveContextObject ( state . getRootContextObject ( ) ) ;
indexValue = this . children [ 0 ] . getValueInternal ( state ) ;
@ -128,52 +127,53 @@ public class Indexer extends SpelNodeImpl {
@@ -128,52 +127,53 @@ public class Indexer extends SpelNodeImpl {
}
}
// Raise a proper exception in case of a null target
if ( target = = null ) {
throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . CANNOT_INDEX_INTO_NULL_VALUE ) ;
}
// Indexing into a Map
if ( targetObject instanceof Map ) {
if ( target instanceof Map ) {
Object key = index ;
if ( targetDescriptor . getMapKeyTypeDescriptor ( ) ! = null ) {
key = state . convertValue ( key , targetDescriptor . getMapKeyTypeDescriptor ( ) ) ;
}
this . indexedType = IndexedType . MAP ;
return new MapIndexingValueRef ( state . getTypeConverter ( ) , ( Map < ? , ? > ) targetObject , key , targetDescriptor ) ;
}
if ( targetObject = = null ) {
throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . CANNOT_INDEX_INTO_NULL_VALUE ) ;
return new MapIndexingValueRef ( state . getTypeConverter ( ) , ( Map < ? , ? > ) target , key , targetDescriptor ) ;
}
// i f the object is something that looks indexable by an integer,
// If the object is something that looks indexable by an integer,
// attempt to treat the index value as a number
if ( targetObject . getClass ( ) . isArray ( ) | | targetObject instanceof Collection | | targetObjec t instanceof String ) {
if ( target . getClass ( ) . isArray ( ) | | target instanceof Collection | | target instanceof String ) {
int idx = ( Integer ) state . convertValue ( index , TypeDescriptor . valueOf ( Integer . class ) ) ;
if ( targetObject . getClass ( ) . isArray ( ) ) {
if ( target . getClass ( ) . isArray ( ) ) {
this . indexedType = IndexedType . ARRAY ;
return new ArrayIndexingValueRef ( state . getTypeConverter ( ) , targetObject , idx , targetDescriptor ) ;
return new ArrayIndexingValueRef ( state . getTypeConverter ( ) , target , idx , targetDescriptor ) ;
}
else if ( targetObject instanceof Collection ) {
if ( targetObject instanceof List ) {
else if ( target instanceof Collection ) {
if ( target instanceof List ) {
this . indexedType = IndexedType . LIST ;
}
return new CollectionIndexingValueRef ( ( Collection < ? > ) targetObject , idx , targetDescriptor ,
return new CollectionIndexingValueRef ( ( Collection < ? > ) target , idx , targetDescriptor ,
state . getTypeConverter ( ) , state . getConfiguration ( ) . isAutoGrowCollections ( ) ,
state . getConfiguration ( ) . getMaximumAutoGrowSize ( ) ) ;
}
else {
this . indexedType = IndexedType . STRING ;
return new StringIndexingLValue ( ( String ) targetObject , idx , targetDescriptor ) ;
return new StringIndexingLValue ( ( String ) target , idx , targetDescriptor ) ;
}
}
// Try and treat the index value as a property of the context object
// TODO could call the conversion service to convert the value to a String
// TODO: could call the conversion service to convert the value to a String
if ( String . class = = indexValue . getTypeDescriptor ( ) . getType ( ) ) {
this . indexedType = IndexedType . OBJECT ;
return new PropertyIndexingValueRef ( targetObject , ( String ) indexValue . getValue ( ) ,
state . getEvaluationContext ( ) , targetDescriptor ) ;
return new PropertyIndexingValueRef (
target , ( String ) index , state . getEvaluationContext ( ) , targetDescriptor ) ;
}
throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . INDEXING_NOT_SUPPORTED_FOR_TYPE ,
targetDescriptor . toString ( ) ) ;
throw new SpelEvaluationException (
getStartPosition ( ) , SpelMessage . INDEXING_NOT_SUPPORTED_FOR_TYPE , targetDescriptor ) ;
}
@Override
@ -188,12 +188,10 @@ public class Indexer extends SpelNodeImpl {
@@ -188,12 +188,10 @@ public class Indexer extends SpelNodeImpl {
return ( this . children [ 0 ] instanceof PropertyOrFieldReference | | this . children [ 0 ] . isCompilable ( ) ) ;
}
else if ( this . indexedType = = IndexedType . OBJECT ) {
// If the string name is changing the accessor is clearly going to change (so compilation is not possible)
if ( this . cachedReadAccessor ! = null & &
( this . cachedReadAccessor instanceof ReflectivePropertyAccessor . OptimalPropertyAccessor ) & &
( getChild ( 0 ) instanceof StringLiteral ) ) {
return true ;
}
// If the string name is changing the accessor is clearly going to change (so no compilation possible)
return ( this . cachedReadAccessor ! = null & &
this . cachedReadAccessor instanceof ReflectivePropertyAccessor . OptimalPropertyAccessor & &
getChild ( 0 ) instanceof StringLiteral ) ;
}
return false ;
}
@ -271,7 +269,8 @@ public class Indexer extends SpelNodeImpl {
@@ -271,7 +269,8 @@ public class Indexer extends SpelNodeImpl {
this . children [ 0 ] . generateCode ( mv , cf ) ;
cf . exitCompilationScope ( ) ;
}
mv . visitMethodInsn ( INVOKEINTERFACE , "java/util/Map" , "get" , "(Ljava/lang/Object;)Ljava/lang/Object;" , true ) ;
mv . visitMethodInsn (
INVOKEINTERFACE , "java/util/Map" , "get" , "(Ljava/lang/Object;)Ljava/lang/Object;" , true ) ;
}
else if ( this . indexedType = = IndexedType . OBJECT ) {
@ -526,8 +525,9 @@ public class Indexer extends SpelNodeImpl {
@@ -526,8 +525,9 @@ public class Indexer extends SpelNodeImpl {
private final TypeDescriptor targetObjectTypeDescriptor ;
public PropertyIndexingValueRef ( Object targetObject , String value , EvaluationContext evaluationContext ,
TypeDescriptor targetObjectTypeDescriptor ) {
public PropertyIndexingValueRef ( Object targetObject , String value ,
EvaluationContext evaluationContext , TypeDescriptor targetObjectTypeDescriptor ) {
this . targetObject = targetObject ;
this . name = value ;
this . evaluationContext = evaluationContext ;
@ -569,11 +569,11 @@ public class Indexer extends SpelNodeImpl {
@@ -569,11 +569,11 @@ public class Indexer extends SpelNodeImpl {
}
}
catch ( AccessException ex ) {
throw new SpelEvaluationException ( getStartPosition ( ) , ex , SpelMessage . INDEXING_NOT_SUPPORTED_FOR_TYPE ,
this . targetObjectTypeDescriptor . toString ( ) ) ;
throw new SpelEvaluationException ( getStartPosition ( ) , ex ,
SpelMessage . INDEXING_NOT_SUPPORTED_FOR_TYPE , this . targetObjectTypeDescriptor . toString ( ) ) ;
}
throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . INDEXING_NOT_SUPPORTED_FOR_TYPE ,
this . targetObjectTypeDescriptor . toString ( ) ) ;
throw new SpelEvaluationException ( getStartPosition ( ) ,
SpelMessage . INDEXING_NOT_SUPPORTED_FOR_TYPE , this . targetObjectTypeDescriptor . toString ( ) ) ;
}
@Override
@ -629,11 +629,12 @@ public class Indexer extends SpelNodeImpl {
@@ -629,11 +629,12 @@ public class Indexer extends SpelNodeImpl {
private final int maximumSize ;
public CollectionIndexingValueRef ( Collection collection , int index , TypeDescriptor collectionEntryType Descriptor ,
public CollectionIndexingValueRef ( Collection collection , int index , TypeDescriptor collectionEntryDescriptor ,
TypeConverter typeConverter , boolean growCollection , int maximumSize ) {
this . collection = collection ;
this . index = index ;
this . collectionEntryDescriptor = collectionEntryType Descriptor ;
this . collectionEntryDescriptor = collectionEntryDescriptor ;
this . typeConverter = typeConverter ;
this . growCollection = growCollection ;
this . maximumSize = maximumSize ;
@ -684,13 +685,14 @@ public class Indexer extends SpelNodeImpl {
@@ -684,13 +685,14 @@ public class Indexer extends SpelNodeImpl {
throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . UNABLE_TO_GROW_COLLECTION ) ;
}
if ( this . collectionEntryDescriptor . getElementTypeDescriptor ( ) = = null ) {
throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE ) ;
throw new SpelEvaluationException (
getStartPosition ( ) , SpelMessage . UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE ) ;
}
TypeDescriptor elementType = this . collectionEntryDescriptor . getElementTypeDescriptor ( ) ;
try {
int newElements = this . index - this . collection . size ( ) ;
while ( newElements > = 0 ) {
( this . collection ) . add ( elementType . getType ( ) . newInstance ( ) ) ;
this . collection . add ( elementType . getType ( ) . newInstance ( ) ) ;
newElements - - ;
}
}