@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
/ *
* Copyright 2002 - 2013 the original author or authors .
* Copyright 2002 - 2014 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 .
@ -34,7 +34,7 @@ import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
@@ -34,7 +34,7 @@ import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
/ * *
* An Indexer can index into some proceeding structure to access a particular piece of it .
* Supported structures are : strings / collections ( lists / sets ) / arrays
* Supported structures are : strings / collections ( lists / sets ) / arrays .
*
* @author Andy Clement
* @author Phillip Webb
@ -88,6 +88,206 @@ public class Indexer extends SpelNodeImpl {
@@ -88,6 +88,206 @@ public class Indexer extends SpelNodeImpl {
}
@Override
protected ValueRef getValueRef ( ExpressionState state ) throws EvaluationException {
TypedValue context = state . getActiveContextObject ( ) ;
Object targetObject = context . getValue ( ) ;
TypeDescriptor targetObjectTypeDescriptor = context . getTypeDescriptor ( ) ;
TypedValue indexValue = null ;
Object index = null ;
// 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 ) ) {
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
try {
state . pushActiveContextObject ( state . getRootContextObject ( ) ) ;
indexValue = this . children [ 0 ] . getValueInternal ( state ) ;
index = indexValue . getValue ( ) ;
}
finally {
state . popActiveContextObject ( ) ;
}
}
// Indexing into a Map
if ( targetObject instanceof Map ) {
Object key = index ;
if ( targetObjectTypeDescriptor . getMapKeyTypeDescriptor ( ) ! = null ) {
key = state . convertValue ( key , targetObjectTypeDescriptor . getMapKeyTypeDescriptor ( ) ) ;
}
return new MapIndexingValueRef ( state . getTypeConverter ( ) , ( Map < ? , ? > ) targetObject , key ,
targetObjectTypeDescriptor ) ;
}
if ( targetObject = = null ) {
throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . CANNOT_INDEX_INTO_NULL_VALUE ) ;
}
// 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 | | targetObject instanceof String ) {
int idx = ( Integer ) state . convertValue ( index , TypeDescriptor . valueOf ( Integer . class ) ) ;
if ( targetObject . getClass ( ) . isArray ( ) ) {
return new ArrayIndexingValueRef ( state . getTypeConverter ( ) , targetObject , idx , targetObjectTypeDescriptor ) ;
}
else if ( targetObject instanceof Collection ) {
return new CollectionIndexingValueRef ( ( Collection < ? > ) targetObject , idx , targetObjectTypeDescriptor ,
state . getTypeConverter ( ) , state . getConfiguration ( ) . isAutoGrowCollections ( ) ,
state . getConfiguration ( ) . getMaximumAutoGrowSize ( ) ) ;
}
else if ( targetObject instanceof String ) {
return new StringIndexingLValue ( ( String ) targetObject , idx , targetObjectTypeDescriptor ) ;
}
}
// 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
if ( indexValue . getTypeDescriptor ( ) . getType ( ) = = String . class ) {
return new PropertyIndexingValueRef ( targetObject , ( String ) indexValue . getValue ( ) ,
state . getEvaluationContext ( ) , targetObjectTypeDescriptor ) ;
}
throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . INDEXING_NOT_SUPPORTED_FOR_TYPE ,
targetObjectTypeDescriptor . toString ( ) ) ;
}
@Override
public String toStringAST ( ) {
StringBuilder sb = new StringBuilder ( ) ;
sb . append ( "[" ) ;
for ( int i = 0 ; i < getChildCount ( ) ; i + + ) {
if ( i > 0 ) {
sb . append ( "," ) ;
}
sb . append ( getChild ( i ) . toStringAST ( ) ) ;
}
sb . append ( "]" ) ;
return sb . toString ( ) ;
}
private void setArrayElement ( TypeConverter converter , Object ctx , int idx , Object newValue ,
Class < ? > arrayComponentType ) throws EvaluationException {
if ( arrayComponentType = = Integer . TYPE ) {
int [ ] array = ( int [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
array [ idx ] = ( Integer ) converter . convertValue ( newValue , TypeDescriptor . forObject ( newValue ) ,
TypeDescriptor . valueOf ( Integer . class ) ) ;
}
else if ( arrayComponentType = = Boolean . TYPE ) {
boolean [ ] array = ( boolean [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
array [ idx ] = ( Boolean ) converter . convertValue ( newValue , TypeDescriptor . forObject ( newValue ) ,
TypeDescriptor . valueOf ( Boolean . class ) ) ;
}
else if ( arrayComponentType = = Character . TYPE ) {
char [ ] array = ( char [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
array [ idx ] = ( Character ) converter . convertValue ( newValue , TypeDescriptor . forObject ( newValue ) ,
TypeDescriptor . valueOf ( Character . class ) ) ;
}
else if ( arrayComponentType = = Long . TYPE ) {
long [ ] array = ( long [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
array [ idx ] = ( Long ) converter . convertValue ( newValue , TypeDescriptor . forObject ( newValue ) ,
TypeDescriptor . valueOf ( Long . class ) ) ;
}
else if ( arrayComponentType = = Short . TYPE ) {
short [ ] array = ( short [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
array [ idx ] = ( Short ) converter . convertValue ( newValue , TypeDescriptor . forObject ( newValue ) ,
TypeDescriptor . valueOf ( Short . class ) ) ;
}
else if ( arrayComponentType = = Double . TYPE ) {
double [ ] array = ( double [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
array [ idx ] = ( Double ) converter . convertValue ( newValue , TypeDescriptor . forObject ( newValue ) ,
TypeDescriptor . valueOf ( Double . class ) ) ;
}
else if ( arrayComponentType = = Float . TYPE ) {
float [ ] array = ( float [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
array [ idx ] = ( Float ) converter . convertValue ( newValue , TypeDescriptor . forObject ( newValue ) ,
TypeDescriptor . valueOf ( Float . class ) ) ;
}
else if ( arrayComponentType = = Byte . TYPE ) {
byte [ ] array = ( byte [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
array [ idx ] = ( Byte ) converter . convertValue ( newValue , TypeDescriptor . forObject ( newValue ) ,
TypeDescriptor . valueOf ( Byte . class ) ) ;
}
else {
Object [ ] array = ( Object [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
array [ idx ] = converter . convertValue ( newValue , TypeDescriptor . forObject ( newValue ) ,
TypeDescriptor . valueOf ( arrayComponentType ) ) ;
}
}
private Object accessArrayElement ( Object ctx , int idx ) throws SpelEvaluationException {
Class < ? > arrayComponentType = ctx . getClass ( ) . getComponentType ( ) ;
if ( arrayComponentType = = Integer . TYPE ) {
int [ ] array = ( int [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
return array [ idx ] ;
}
else if ( arrayComponentType = = Boolean . TYPE ) {
boolean [ ] array = ( boolean [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
return array [ idx ] ;
}
else if ( arrayComponentType = = Character . TYPE ) {
char [ ] array = ( char [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
return array [ idx ] ;
}
else if ( arrayComponentType = = Long . TYPE ) {
long [ ] array = ( long [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
return array [ idx ] ;
}
else if ( arrayComponentType = = Short . TYPE ) {
short [ ] array = ( short [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
return array [ idx ] ;
}
else if ( arrayComponentType = = Double . TYPE ) {
double [ ] array = ( double [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
return array [ idx ] ;
}
else if ( arrayComponentType = = Float . TYPE ) {
float [ ] array = ( float [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
return array [ idx ] ;
}
else if ( arrayComponentType = = Byte . TYPE ) {
byte [ ] array = ( byte [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
return array [ idx ] ;
}
else {
Object [ ] array = ( Object [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
return array [ idx ] ;
}
}
private void checkAccess ( int arrayLength , int index ) throws SpelEvaluationException {
if ( index > arrayLength ) {
throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . ARRAY_INDEX_OUT_OF_BOUNDS ,
arrayLength , index ) ;
}
}
private class ArrayIndexingValueRef implements ValueRef {
private final TypeConverter typeConverter ;
@ -127,7 +327,7 @@ public class Indexer extends SpelNodeImpl {
@@ -127,7 +327,7 @@ public class Indexer extends SpelNodeImpl {
@SuppressWarnings ( { "rawtypes" , "unchecked" } )
private class MapIndexingValueRef implements ValueRef {
private static class MapIndexingValueRef implements ValueRef {
private final TypeConverter typeConverter ;
@ -137,16 +337,13 @@ public class Indexer extends SpelNodeImpl {
@@ -137,16 +337,13 @@ public class Indexer extends SpelNodeImpl {
private final TypeDescriptor mapEntryTypeDescriptor ;
MapIndexingValueRef ( TypeConverter typeConverter , Map map , Object key ,
TypeDescriptor mapEntryTypeDescriptor ) {
public MapIndexingValueRef ( TypeConverter typeConverter , Map map , Object key , TypeDescriptor mapEntryTypeDescriptor ) {
this . typeConverter = typeConverter ;
this . map = map ;
this . key = key ;
this . mapEntryTypeDescriptor = mapEntryTypeDescriptor ;
}
@Override
public TypedValue getValue ( ) {
Object value = this . map . get ( this . key ) ;
@ -180,7 +377,6 @@ public class Indexer extends SpelNodeImpl {
@@ -180,7 +377,6 @@ public class Indexer extends SpelNodeImpl {
private final TypeDescriptor targetObjectTypeDescriptor ;
public PropertyIndexingValueRef ( Object targetObject , String value , EvaluationContext evaluationContext ,
TypeDescriptor targetObjectTypeDescriptor ) {
this . targetObject = targetObject ;
@ -194,15 +390,14 @@ public class Indexer extends SpelNodeImpl {
@@ -194,15 +390,14 @@ public class Indexer extends SpelNodeImpl {
public TypedValue getValue ( ) {
Class < ? > targetObjectRuntimeClass = getObjectClass ( this . targetObject ) ;
try {
if ( Indexer . this . cachedReadName ! = null & & Indexer . this . cachedReadName . equals ( this . name ) & & Indexer . this . cachedReadTargetType ! = null & &
if ( Indexer . this . cachedReadName ! = null & & Indexer . this . cachedReadName . equals ( this . name ) & &
Indexer . this . cachedReadTargetType ! = null & &
Indexer . this . cachedReadTargetType . equals ( targetObjectRuntimeClass ) ) {
// i t is OK to use the cached accessor
// I t is OK to use the cached accessor
return Indexer . this . cachedReadAccessor . read ( this . evaluationContext , this . targetObject , this . name ) ;
}
List < PropertyAccessor > accessorsToTry = AstUtils . getPropertyAccessorsToTry (
targetObjectRuntimeClass , this . evaluationContext . getPropertyAccessors ( ) ) ;
if ( accessorsToTry ! = null ) {
for ( PropertyAccessor accessor : accessorsToTry ) {
if ( accessor . canRead ( this . evaluationContext , this . targetObject , this . name ) ) {
@ -230,9 +425,10 @@ public class Indexer extends SpelNodeImpl {
@@ -230,9 +425,10 @@ public class Indexer extends SpelNodeImpl {
public void setValue ( Object newValue ) {
Class < ? > contextObjectClass = getObjectClass ( this . targetObject ) ;
try {
if ( Indexer . this . cachedWriteName ! = null & & Indexer . this . cachedWriteName . equals ( this . name ) & & Indexer . this . cachedWriteTargetType ! = null & &
if ( Indexer . this . cachedWriteName ! = null & & Indexer . this . cachedWriteName . equals ( this . name ) & &
Indexer . this . cachedWriteTargetType ! = null & &
Indexer . this . cachedWriteTargetType . equals ( contextObjectClass ) ) {
// i t is OK to use the cached accessor
// I t is OK to use the cached accessor
Indexer . this . cachedWriteAccessor . write ( this . evaluationContext , this . targetObject , this . name , newValue ) ;
return ;
}
@ -270,7 +466,7 @@ public class Indexer extends SpelNodeImpl {
@@ -270,7 +466,7 @@ public class Indexer extends SpelNodeImpl {
private final int index ;
private final TypeDescriptor collectionEntryType Descriptor ;
private final TypeDescriptor collectionEntryDescriptor ;
private final TypeConverter typeConverter ;
@ -278,12 +474,11 @@ public class Indexer extends SpelNodeImpl {
@@ -278,12 +474,11 @@ public class Indexer extends SpelNodeImpl {
private final int maximumSize ;
CollectionIndexingValueRef ( Collection collection , int index , TypeDescriptor collectionEntryTypeDescriptor ,
public CollectionIndexingValueRef ( Collection collection , int index , TypeDescriptor collectionEntryTypeDescriptor ,
TypeConverter typeConverter , boolean growCollection , int maximumSize ) {
this . collection = collection ;
this . index = index ;
this . collectionEntryType Descriptor = collectionEntryTypeDescriptor ;
this . collectionEntryDescriptor = collectionEntryTypeDescriptor ;
this . typeConverter = typeConverter ;
this . growCollection = growCollection ;
this . maximumSize = maximumSize ;
@ -295,12 +490,12 @@ public class Indexer extends SpelNodeImpl {
@@ -295,12 +490,12 @@ public class Indexer extends SpelNodeImpl {
growCollectionIfNecessary ( ) ;
if ( this . collection instanceof List ) {
Object o = ( ( List ) this . collection ) . get ( this . index ) ;
return new TypedValue ( o , this . collectionEntryType Descriptor . elementTypeDescriptor ( o ) ) ;
return new TypedValue ( o , this . collectionEntryDescriptor . elementTypeDescriptor ( o ) ) ;
}
int pos = 0 ;
for ( Object o : this . collection ) {
if ( pos = = this . index ) {
return new TypedValue ( o , this . collectionEntryType Descriptor . elementTypeDescriptor ( o ) ) ;
return new TypedValue ( o , this . collectionEntryDescriptor . elementTypeDescriptor ( o ) ) ;
}
pos + + ;
}
@ -312,35 +507,31 @@ public class Indexer extends SpelNodeImpl {
@@ -312,35 +507,31 @@ public class Indexer extends SpelNodeImpl {
growCollectionIfNecessary ( ) ;
if ( this . collection instanceof List ) {
List list = ( List ) this . collection ;
if ( this . collectionEntryType Descriptor . getElementTypeDescriptor ( ) ! = null ) {
if ( this . collectionEntryDescriptor . getElementTypeDescriptor ( ) ! = null ) {
newValue = this . typeConverter . convertValue ( newValue , TypeDescriptor . forObject ( newValue ) ,
this . collectionEntryType Descriptor . getElementTypeDescriptor ( ) ) ;
this . collectionEntryDescriptor . getElementTypeDescriptor ( ) ) ;
}
list . set ( this . index , newValue ) ;
}
else {
throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . INDEXING_NOT_SUPPORTED_FOR_TYPE ,
this . collectionEntryType Descriptor . toString ( ) ) ;
this . collectionEntryDescriptor . toString ( ) ) ;
}
}
private void growCollectionIfNecessary ( ) {
if ( this . index > = this . collection . size ( ) ) {
if ( ! this . growCollection ) {
throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . COLLECTION_INDEX_OUT_OF_BOUNDS ,
this . collection . size ( ) , this . index ) ;
}
if ( this . index > = this . maximumSize ) {
throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . UNABLE_TO_GROW_COLLECTION ) ;
}
if ( this . collectionEntryTypeDescriptor . getElementTypeDescriptor ( ) = = null ) {
if ( this . collectionEntryDescriptor . getElementTypeDescriptor ( ) = = null ) {
throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE ) ;
}
TypeDescriptor elementType = this . collectionEntryTypeDescriptor . getElementTypeDescriptor ( ) ;
TypeDescriptor elementType = this . collectionEntryDescriptor . getElementTypeDescriptor ( ) ;
try {
int newElements = this . index - this . collection . size ( ) ;
while ( newElements > = 0 ) {
@ -369,14 +560,12 @@ public class Indexer extends SpelNodeImpl {
@@ -369,14 +560,12 @@ public class Indexer extends SpelNodeImpl {
private final TypeDescriptor typeDescriptor ;
public StringIndexingLValue ( String target , int index , TypeDescriptor typeDescriptor ) {
this . target = target ;
this . index = index ;
this . typeDescriptor = typeDescriptor ;
}
@Override
public TypedValue getValue ( ) {
if ( this . index > = this . target . length ( ) ) {
@ -398,204 +587,4 @@ public class Indexer extends SpelNodeImpl {
@@ -398,204 +587,4 @@ public class Indexer extends SpelNodeImpl {
}
}
@Override
protected ValueRef getValueRef ( ExpressionState state ) throws EvaluationException {
TypedValue context = state . getActiveContextObject ( ) ;
Object targetObject = context . getValue ( ) ;
TypeDescriptor targetObjectTypeDescriptor = context . getTypeDescriptor ( ) ;
TypedValue indexValue = null ;
Object index = null ;
// 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 ) ) {
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
try {
state . pushActiveContextObject ( state . getRootContextObject ( ) ) ;
indexValue = this . children [ 0 ] . getValueInternal ( state ) ;
index = indexValue . getValue ( ) ;
}
finally {
state . popActiveContextObject ( ) ;
}
}
// Indexing into a Map
if ( targetObject instanceof Map ) {
Object key = index ;
if ( targetObjectTypeDescriptor . getMapKeyTypeDescriptor ( ) ! = null ) {
key = state . convertValue ( key , targetObjectTypeDescriptor . getMapKeyTypeDescriptor ( ) ) ;
}
return new MapIndexingValueRef ( state . getTypeConverter ( ) , ( Map < ? , ? > ) targetObject , key ,
targetObjectTypeDescriptor ) ;
}
if ( targetObject = = null ) {
throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . CANNOT_INDEX_INTO_NULL_VALUE ) ;
}
// 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 | | targetObject instanceof String ) {
int idx = ( Integer ) state . convertValue ( index , TypeDescriptor . valueOf ( Integer . class ) ) ;
if ( targetObject . getClass ( ) . isArray ( ) ) {
return new ArrayIndexingValueRef ( state . getTypeConverter ( ) , targetObject , idx , targetObjectTypeDescriptor ) ;
}
else if ( targetObject instanceof Collection ) {
return new CollectionIndexingValueRef ( ( Collection < ? > ) targetObject , idx , targetObjectTypeDescriptor ,
state . getTypeConverter ( ) , state . getConfiguration ( ) . isAutoGrowCollections ( ) ,
state . getConfiguration ( ) . getMaximumAutoGrowSize ( ) ) ;
}
else if ( targetObject instanceof String ) {
return new StringIndexingLValue ( ( String ) targetObject , idx , targetObjectTypeDescriptor ) ;
}
}
// 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
if ( indexValue . getTypeDescriptor ( ) . getType ( ) = = String . class ) {
return new PropertyIndexingValueRef ( targetObject , ( String ) indexValue . getValue ( ) ,
state . getEvaluationContext ( ) , targetObjectTypeDescriptor ) ;
}
throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . INDEXING_NOT_SUPPORTED_FOR_TYPE ,
targetObjectTypeDescriptor . toString ( ) ) ;
}
@Override
public String toStringAST ( ) {
StringBuilder sb = new StringBuilder ( ) ;
sb . append ( "[" ) ;
for ( int i = 0 ; i < getChildCount ( ) ; i + + ) {
if ( i > 0 ) {
sb . append ( "," ) ;
}
sb . append ( getChild ( i ) . toStringAST ( ) ) ;
}
sb . append ( "]" ) ;
return sb . toString ( ) ;
}
private void setArrayElement ( TypeConverter converter , Object ctx , int idx , Object newValue , Class < ? > clazz )
throws EvaluationException {
Class < ? > arrayComponentType = clazz ;
if ( arrayComponentType = = Integer . TYPE ) {
int [ ] array = ( int [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
array [ idx ] = ( Integer ) converter . convertValue ( newValue , TypeDescriptor . forObject ( newValue ) ,
TypeDescriptor . valueOf ( Integer . class ) ) ;
}
else if ( arrayComponentType = = Boolean . TYPE ) {
boolean [ ] array = ( boolean [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
array [ idx ] = ( Boolean ) converter . convertValue ( newValue , TypeDescriptor . forObject ( newValue ) ,
TypeDescriptor . valueOf ( Boolean . class ) ) ;
}
else if ( arrayComponentType = = Character . TYPE ) {
char [ ] array = ( char [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
array [ idx ] = ( Character ) converter . convertValue ( newValue , TypeDescriptor . forObject ( newValue ) ,
TypeDescriptor . valueOf ( Character . class ) ) ;
}
else if ( arrayComponentType = = Long . TYPE ) {
long [ ] array = ( long [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
array [ idx ] = ( Long ) converter . convertValue ( newValue , TypeDescriptor . forObject ( newValue ) ,
TypeDescriptor . valueOf ( Long . class ) ) ;
}
else if ( arrayComponentType = = Short . TYPE ) {
short [ ] array = ( short [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
array [ idx ] = ( Short ) converter . convertValue ( newValue , TypeDescriptor . forObject ( newValue ) ,
TypeDescriptor . valueOf ( Short . class ) ) ;
}
else if ( arrayComponentType = = Double . TYPE ) {
double [ ] array = ( double [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
array [ idx ] = ( Double ) converter . convertValue ( newValue , TypeDescriptor . forObject ( newValue ) ,
TypeDescriptor . valueOf ( Double . class ) ) ;
}
else if ( arrayComponentType = = Float . TYPE ) {
float [ ] array = ( float [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
array [ idx ] = ( Float ) converter . convertValue ( newValue , TypeDescriptor . forObject ( newValue ) ,
TypeDescriptor . valueOf ( Float . class ) ) ;
}
else if ( arrayComponentType = = Byte . TYPE ) {
byte [ ] array = ( byte [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
array [ idx ] = ( Byte ) converter . convertValue ( newValue , TypeDescriptor . forObject ( newValue ) ,
TypeDescriptor . valueOf ( Byte . class ) ) ;
}
else {
Object [ ] array = ( Object [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
array [ idx ] = converter . convertValue ( newValue , TypeDescriptor . forObject ( newValue ) ,
TypeDescriptor . valueOf ( clazz ) ) ;
}
}
private Object accessArrayElement ( Object ctx , int idx ) throws SpelEvaluationException {
Class < ? > arrayComponentType = ctx . getClass ( ) . getComponentType ( ) ;
if ( arrayComponentType = = Integer . TYPE ) {
int [ ] array = ( int [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
return array [ idx ] ;
}
else if ( arrayComponentType = = Boolean . TYPE ) {
boolean [ ] array = ( boolean [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
return array [ idx ] ;
}
else if ( arrayComponentType = = Character . TYPE ) {
char [ ] array = ( char [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
return array [ idx ] ;
}
else if ( arrayComponentType = = Long . TYPE ) {
long [ ] array = ( long [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
return array [ idx ] ;
}
else if ( arrayComponentType = = Short . TYPE ) {
short [ ] array = ( short [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
return array [ idx ] ;
}
else if ( arrayComponentType = = Double . TYPE ) {
double [ ] array = ( double [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
return array [ idx ] ;
}
else if ( arrayComponentType = = Float . TYPE ) {
float [ ] array = ( float [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
return array [ idx ] ;
}
else if ( arrayComponentType = = Byte . TYPE ) {
byte [ ] array = ( byte [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
return array [ idx ] ;
}
else {
Object [ ] array = ( Object [ ] ) ctx ;
checkAccess ( array . length , idx ) ;
return array [ idx ] ;
}
}
private void checkAccess ( int arrayLength , int index ) throws SpelEvaluationException {
if ( index > arrayLength ) {
throw new SpelEvaluationException ( getStartPosition ( ) , SpelMessage . ARRAY_INDEX_OUT_OF_BOUNDS ,
arrayLength , index ) ;
}
}
}