|
|
|
@ -48,22 +48,30 @@ public class Indexer extends SpelNodeImpl { |
|
|
|
// If the name and target type match these cached values then the cachedReadAccessor
|
|
|
|
// If the name and target type match these cached values then the cachedReadAccessor
|
|
|
|
// is used to read the property. If they do not match, the correct accessor is
|
|
|
|
// is used to read the property. If they do not match, the correct accessor is
|
|
|
|
// discovered and then cached for later use.
|
|
|
|
// discovered and then cached for later use.
|
|
|
|
|
|
|
|
|
|
|
|
private String cachedReadName; |
|
|
|
private String cachedReadName; |
|
|
|
|
|
|
|
|
|
|
|
private Class<?> cachedReadTargetType; |
|
|
|
private Class<?> cachedReadTargetType; |
|
|
|
|
|
|
|
|
|
|
|
private PropertyAccessor cachedReadAccessor; |
|
|
|
private PropertyAccessor cachedReadAccessor; |
|
|
|
|
|
|
|
|
|
|
|
// These fields are used when the indexer is being used as a property write accessor.
|
|
|
|
// These fields are used when the indexer is being used as a property write accessor.
|
|
|
|
// If the name and target type match these cached values then the cachedWriteAccessor
|
|
|
|
// If the name and target type match these cached values then the cachedWriteAccessor
|
|
|
|
// is used to write the property. If they do not match, the correct accessor is
|
|
|
|
// is used to write the property. If they do not match, the correct accessor is
|
|
|
|
// discovered and then cached for later use.
|
|
|
|
// discovered and then cached for later use.
|
|
|
|
|
|
|
|
|
|
|
|
private String cachedWriteName; |
|
|
|
private String cachedWriteName; |
|
|
|
|
|
|
|
|
|
|
|
private Class<?> cachedWriteTargetType; |
|
|
|
private Class<?> cachedWriteTargetType; |
|
|
|
|
|
|
|
|
|
|
|
private PropertyAccessor cachedWriteAccessor; |
|
|
|
private PropertyAccessor cachedWriteAccessor; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Indexer(int pos, SpelNodeImpl expr) { |
|
|
|
public Indexer(int pos, SpelNodeImpl expr) { |
|
|
|
super(pos, expr); |
|
|
|
super(pos, expr); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException { |
|
|
|
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException { |
|
|
|
return getValueRef(state).getValue(); |
|
|
|
return getValueRef(state).getValue(); |
|
|
|
@ -75,20 +83,22 @@ public class Indexer extends SpelNodeImpl { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public boolean isWritable(ExpressionState expressionState) |
|
|
|
public boolean isWritable(ExpressionState expressionState) throws SpelEvaluationException { |
|
|
|
throws SpelEvaluationException { |
|
|
|
|
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
class ArrayIndexingValueRef implements ValueRef { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private TypeConverter typeConverter; |
|
|
|
private class ArrayIndexingValueRef implements ValueRef { |
|
|
|
private Object array; |
|
|
|
|
|
|
|
private int idx; |
|
|
|
private final TypeConverter typeConverter; |
|
|
|
private TypeDescriptor typeDescriptor; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ArrayIndexingValueRef(TypeConverter typeConverter, Object array, |
|
|
|
private final Object array; |
|
|
|
int idx, TypeDescriptor typeDescriptor) { |
|
|
|
|
|
|
|
|
|
|
|
private final int idx; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final TypeDescriptor typeDescriptor; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ArrayIndexingValueRef(TypeConverter typeConverter, Object array, int idx, TypeDescriptor typeDescriptor) { |
|
|
|
this.typeConverter = typeConverter; |
|
|
|
this.typeConverter = typeConverter; |
|
|
|
this.array = array; |
|
|
|
this.array = array; |
|
|
|
this.idx = idx; |
|
|
|
this.idx = idx; |
|
|
|
@ -96,14 +106,13 @@ public class Indexer extends SpelNodeImpl { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public TypedValue getValue() { |
|
|
|
public TypedValue getValue() { |
|
|
|
Object arrayElement = accessArrayElement(array, idx); |
|
|
|
Object arrayElement = accessArrayElement(this.array, this.idx); |
|
|
|
return new TypedValue(arrayElement, |
|
|
|
return new TypedValue(arrayElement, this.typeDescriptor.elementTypeDescriptor(arrayElement)); |
|
|
|
typeDescriptor.elementTypeDescriptor(arrayElement)); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void setValue(Object newValue) { |
|
|
|
public void setValue(Object newValue) { |
|
|
|
setArrayElement(typeConverter, array, idx, newValue, typeDescriptor |
|
|
|
setArrayElement(this.typeConverter, this.array, this.idx, newValue, |
|
|
|
.getElementTypeDescriptor().getType()); |
|
|
|
this.typeDescriptor.getElementTypeDescriptor().getType()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public boolean isWritable() { |
|
|
|
public boolean isWritable() { |
|
|
|
@ -111,16 +120,19 @@ public class Indexer extends SpelNodeImpl { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings({ "rawtypes", "unchecked" }) |
|
|
|
|
|
|
|
class MapIndexingValueRef implements ValueRef { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private TypeConverter typeConverter; |
|
|
|
@SuppressWarnings({"rawtypes", "unchecked"}) |
|
|
|
private Map map; |
|
|
|
private class MapIndexingValueRef implements ValueRef { |
|
|
|
private Object key; |
|
|
|
|
|
|
|
private TypeDescriptor mapEntryTypeDescriptor; |
|
|
|
private final TypeConverter typeConverter; |
|
|
|
|
|
|
|
|
|
|
|
MapIndexingValueRef(TypeConverter typeConverter, Map map, Object key, |
|
|
|
private final Map map; |
|
|
|
TypeDescriptor mapEntryTypeDescriptor) { |
|
|
|
|
|
|
|
|
|
|
|
private final Object key; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final TypeDescriptor mapEntryTypeDescriptor; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MapIndexingValueRef(TypeConverter typeConverter, Map map, Object key, TypeDescriptor mapEntryTypeDescriptor) { |
|
|
|
this.typeConverter = typeConverter; |
|
|
|
this.typeConverter = typeConverter; |
|
|
|
this.map = map; |
|
|
|
this.map = map; |
|
|
|
this.key = key; |
|
|
|
this.key = key; |
|
|
|
@ -128,35 +140,35 @@ public class Indexer extends SpelNodeImpl { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public TypedValue getValue() { |
|
|
|
public TypedValue getValue() { |
|
|
|
Object value = map.get(key); |
|
|
|
Object value = this.map.get(this.key); |
|
|
|
return new TypedValue(value, |
|
|
|
return new TypedValue(value, this.mapEntryTypeDescriptor.getMapValueTypeDescriptor(value)); |
|
|
|
mapEntryTypeDescriptor.getMapValueTypeDescriptor(value)); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void setValue(Object newValue) { |
|
|
|
public void setValue(Object newValue) { |
|
|
|
if (mapEntryTypeDescriptor.getMapValueTypeDescriptor() != null) { |
|
|
|
if (this.mapEntryTypeDescriptor.getMapValueTypeDescriptor() != null) { |
|
|
|
newValue = typeConverter.convertValue(newValue, |
|
|
|
newValue = this.typeConverter.convertValue(newValue, TypeDescriptor.forObject(newValue), |
|
|
|
TypeDescriptor.forObject(newValue), |
|
|
|
this.mapEntryTypeDescriptor.getMapValueTypeDescriptor()); |
|
|
|
mapEntryTypeDescriptor.getMapValueTypeDescriptor()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
map.put(key, newValue); |
|
|
|
this.map.put(this.key, newValue); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public boolean isWritable() { |
|
|
|
public boolean isWritable() { |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
class PropertyIndexingValueRef implements ValueRef { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Object targetObject; |
|
|
|
private class PropertyIndexingValueRef implements ValueRef { |
|
|
|
private String name; |
|
|
|
|
|
|
|
private EvaluationContext eContext; |
|
|
|
|
|
|
|
private TypeDescriptor td; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public PropertyIndexingValueRef(Object targetObject, String value, |
|
|
|
private final Object targetObject; |
|
|
|
EvaluationContext evaluationContext, |
|
|
|
|
|
|
|
|
|
|
|
private final String name; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final EvaluationContext eContext; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final TypeDescriptor td; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public PropertyIndexingValueRef(Object targetObject, String value, EvaluationContext evaluationContext, |
|
|
|
TypeDescriptor targetObjectTypeDescriptor) { |
|
|
|
TypeDescriptor targetObjectTypeDescriptor) { |
|
|
|
this.targetObject = targetObject; |
|
|
|
this.targetObject = targetObject; |
|
|
|
this.name = value; |
|
|
|
this.name = value; |
|
|
|
@ -166,78 +178,63 @@ public class Indexer extends SpelNodeImpl { |
|
|
|
|
|
|
|
|
|
|
|
public TypedValue getValue() { |
|
|
|
public TypedValue getValue() { |
|
|
|
Class<?> targetObjectRuntimeClass = getObjectClass(targetObject); |
|
|
|
Class<?> targetObjectRuntimeClass = getObjectClass(targetObject); |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
if (cachedReadName != null |
|
|
|
if (cachedReadName != null && cachedReadName.equals(name) && cachedReadTargetType != null && |
|
|
|
&& cachedReadName.equals(name) |
|
|
|
cachedReadTargetType.equals(targetObjectRuntimeClass)) { |
|
|
|
&& cachedReadTargetType != null |
|
|
|
|
|
|
|
&& cachedReadTargetType |
|
|
|
|
|
|
|
.equals(targetObjectRuntimeClass)) { |
|
|
|
|
|
|
|
// it is OK to use the cached accessor
|
|
|
|
// it is OK to use the cached accessor
|
|
|
|
return cachedReadAccessor |
|
|
|
return cachedReadAccessor.read(this.eContext, this.targetObject, this.name); |
|
|
|
.read(eContext, targetObject, name); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
List<PropertyAccessor> accessorsToTry = |
|
|
|
List<PropertyAccessor> accessorsToTry = AstUtils |
|
|
|
AstUtils.getPropertyAccessorsToTry(targetObjectRuntimeClass, eContext.getPropertyAccessors()); |
|
|
|
.getPropertyAccessorsToTry(targetObjectRuntimeClass, |
|
|
|
|
|
|
|
eContext.getPropertyAccessors()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (accessorsToTry != null) { |
|
|
|
if (accessorsToTry != null) { |
|
|
|
for (PropertyAccessor accessor : accessorsToTry) { |
|
|
|
for (PropertyAccessor accessor : accessorsToTry) { |
|
|
|
if (accessor.canRead(eContext, targetObject, name)) { |
|
|
|
if (accessor.canRead(this.eContext, this.targetObject, this.name)) { |
|
|
|
if (accessor instanceof ReflectivePropertyAccessor) { |
|
|
|
if (accessor instanceof ReflectivePropertyAccessor) { |
|
|
|
accessor = ((ReflectivePropertyAccessor) accessor) |
|
|
|
accessor = ((ReflectivePropertyAccessor) accessor).createOptimalAccessor( |
|
|
|
.createOptimalAccessor(eContext, |
|
|
|
this.eContext, this.targetObject, this.name); |
|
|
|
targetObject, name); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
cachedReadAccessor = accessor; |
|
|
|
cachedReadAccessor = accessor; |
|
|
|
cachedReadName = name; |
|
|
|
cachedReadName = this.name; |
|
|
|
cachedReadTargetType = targetObjectRuntimeClass; |
|
|
|
cachedReadTargetType = targetObjectRuntimeClass; |
|
|
|
return accessor.read(eContext, targetObject, name); |
|
|
|
return accessor.read(this.eContext, this.targetObject, this.name); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (AccessException e) { |
|
|
|
|
|
|
|
throw new SpelEvaluationException(getStartPosition(), e, |
|
|
|
|
|
|
|
SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, |
|
|
|
|
|
|
|
td.toString()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
throw new SpelEvaluationException(getStartPosition(), |
|
|
|
catch (AccessException ex) { |
|
|
|
SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, td.toString()); |
|
|
|
throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, |
|
|
|
|
|
|
|
this.td.toString()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
throw new SpelEvaluationException(getStartPosition(), SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, |
|
|
|
|
|
|
|
this.td.toString()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void setValue(Object newValue) { |
|
|
|
public void setValue(Object newValue) { |
|
|
|
Class<?> contextObjectClass = getObjectClass(targetObject); |
|
|
|
Class<?> contextObjectClass = getObjectClass(targetObject); |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
if (cachedWriteName != null && cachedWriteName.equals(name) |
|
|
|
if (cachedWriteName != null && cachedWriteName.equals(name) && cachedWriteTargetType != null && |
|
|
|
&& cachedWriteTargetType != null |
|
|
|
cachedWriteTargetType.equals(contextObjectClass)) { |
|
|
|
&& cachedWriteTargetType.equals(contextObjectClass)) { |
|
|
|
|
|
|
|
// it is OK to use the cached accessor
|
|
|
|
// it is OK to use the cached accessor
|
|
|
|
cachedWriteAccessor.write(eContext, targetObject, name, |
|
|
|
cachedWriteAccessor.write(this.eContext, this.targetObject, this.name, newValue); |
|
|
|
newValue); |
|
|
|
|
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
List<PropertyAccessor> accessorsToTry = |
|
|
|
List<PropertyAccessor> accessorsToTry = AstUtils |
|
|
|
AstUtils.getPropertyAccessorsToTry(contextObjectClass, this.eContext.getPropertyAccessors()); |
|
|
|
.getPropertyAccessorsToTry(contextObjectClass, |
|
|
|
|
|
|
|
eContext.getPropertyAccessors()); |
|
|
|
|
|
|
|
if (accessorsToTry != null) { |
|
|
|
if (accessorsToTry != null) { |
|
|
|
for (PropertyAccessor accessor : accessorsToTry) { |
|
|
|
for (PropertyAccessor accessor : accessorsToTry) { |
|
|
|
if (accessor.canWrite(eContext, targetObject, name)) { |
|
|
|
if (accessor.canWrite(this.eContext, this.targetObject, this.name)) { |
|
|
|
cachedWriteName = name; |
|
|
|
cachedWriteName = this.name; |
|
|
|
cachedWriteTargetType = contextObjectClass; |
|
|
|
cachedWriteTargetType = contextObjectClass; |
|
|
|
cachedWriteAccessor = accessor; |
|
|
|
cachedWriteAccessor = accessor; |
|
|
|
accessor.write(eContext, targetObject, name, |
|
|
|
accessor.write(this.eContext, this.targetObject, this.name, newValue); |
|
|
|
newValue); |
|
|
|
|
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (AccessException ae) { |
|
|
|
} |
|
|
|
throw new SpelEvaluationException(getStartPosition(), ae, |
|
|
|
catch (AccessException ex) { |
|
|
|
SpelMessage.EXCEPTION_DURING_PROPERTY_WRITE, name, |
|
|
|
throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.EXCEPTION_DURING_PROPERTY_WRITE, |
|
|
|
ae.getMessage()); |
|
|
|
this.name, ex.getMessage()); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -246,70 +243,74 @@ public class Indexer extends SpelNodeImpl { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings({ "rawtypes", "unchecked" }) |
|
|
|
@SuppressWarnings({ "rawtypes", "unchecked" }) |
|
|
|
class CollectionIndexingValueRef implements ValueRef { |
|
|
|
private class CollectionIndexingValueRef implements ValueRef { |
|
|
|
|
|
|
|
|
|
|
|
private TypeConverter typeConverter; |
|
|
|
private final Collection collection; |
|
|
|
private Collection collection; |
|
|
|
|
|
|
|
private int index; |
|
|
|
|
|
|
|
private TypeDescriptor collectionEntryTypeDescriptor; |
|
|
|
|
|
|
|
private boolean growCollection; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CollectionIndexingValueRef(Collection collection, int index, |
|
|
|
private final int index; |
|
|
|
TypeDescriptor collectionEntryTypeDescriptor, TypeConverter typeConverter, boolean growCollection) { |
|
|
|
|
|
|
|
this.typeConverter = typeConverter; |
|
|
|
private final TypeDescriptor collectionEntryTypeDescriptor; |
|
|
|
this.growCollection = growCollection; |
|
|
|
|
|
|
|
|
|
|
|
private final TypeConverter typeConverter; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final boolean growCollection; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CollectionIndexingValueRef(Collection collection, int index, TypeDescriptor collectionEntryTypeDescriptor, |
|
|
|
|
|
|
|
TypeConverter typeConverter, boolean growCollection) { |
|
|
|
this.collection = collection; |
|
|
|
this.collection = collection; |
|
|
|
this.index = index; |
|
|
|
this.index = index; |
|
|
|
this.collectionEntryTypeDescriptor = collectionEntryTypeDescriptor; |
|
|
|
this.collectionEntryTypeDescriptor = collectionEntryTypeDescriptor; |
|
|
|
|
|
|
|
this.typeConverter = typeConverter; |
|
|
|
|
|
|
|
this.growCollection = growCollection; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public TypedValue getValue() { |
|
|
|
public TypedValue getValue() { |
|
|
|
if (index >= collection.size()) { |
|
|
|
if (this.index >= this.collection.size()) { |
|
|
|
if (growCollection) { |
|
|
|
if (this.growCollection) { |
|
|
|
growCollection(collectionEntryTypeDescriptor,index,collection); |
|
|
|
growCollection(this.collectionEntryTypeDescriptor, this.index, this.collection); |
|
|
|
} else { |
|
|
|
} |
|
|
|
throw new SpelEvaluationException(getStartPosition(), |
|
|
|
else { |
|
|
|
SpelMessage.COLLECTION_INDEX_OUT_OF_BOUNDS, |
|
|
|
throw new SpelEvaluationException(getStartPosition(), SpelMessage.COLLECTION_INDEX_OUT_OF_BOUNDS, |
|
|
|
collection.size(), index); |
|
|
|
this.collection.size(), this.index); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (this.collection instanceof List) { |
|
|
|
|
|
|
|
Object o = ((List) this.collection).get(this.index); |
|
|
|
|
|
|
|
return new TypedValue(o, this.collectionEntryTypeDescriptor.elementTypeDescriptor(o)); |
|
|
|
|
|
|
|
} |
|
|
|
int pos = 0; |
|
|
|
int pos = 0; |
|
|
|
for (Object o : collection) { |
|
|
|
for (Object o : this.collection) { |
|
|
|
if (pos == index) { |
|
|
|
if (pos == this.index) { |
|
|
|
return new TypedValue(o, |
|
|
|
return new TypedValue(o, this.collectionEntryTypeDescriptor.elementTypeDescriptor(o)); |
|
|
|
collectionEntryTypeDescriptor |
|
|
|
|
|
|
|
.elementTypeDescriptor(o)); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
pos++; |
|
|
|
pos++; |
|
|
|
} |
|
|
|
} |
|
|
|
throw new IllegalStateException(); |
|
|
|
throw new IllegalStateException("Failed to find indexed element " + this.index + ": " + this.collection); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void setValue(Object newValue) { |
|
|
|
public void setValue(Object newValue) { |
|
|
|
if (index >= collection.size()) { |
|
|
|
if (this.index >= this.collection.size()) { |
|
|
|
if (growCollection) { |
|
|
|
if (this.growCollection) { |
|
|
|
growCollection(collectionEntryTypeDescriptor, index, collection); |
|
|
|
growCollection(this.collectionEntryTypeDescriptor, this.index, this.collection); |
|
|
|
} else { |
|
|
|
} |
|
|
|
throw new SpelEvaluationException(getStartPosition(), |
|
|
|
else { |
|
|
|
SpelMessage.COLLECTION_INDEX_OUT_OF_BOUNDS, |
|
|
|
throw new SpelEvaluationException(getStartPosition(), SpelMessage.COLLECTION_INDEX_OUT_OF_BOUNDS, |
|
|
|
collection.size(), index); |
|
|
|
this.collection.size(), this.index); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (collection instanceof List) { |
|
|
|
if (this.collection instanceof List) { |
|
|
|
List list = (List) collection; |
|
|
|
List list = (List) this.collection; |
|
|
|
if (collectionEntryTypeDescriptor.getElementTypeDescriptor() != null) { |
|
|
|
if (this.collectionEntryTypeDescriptor.getElementTypeDescriptor() != null) { |
|
|
|
newValue = typeConverter.convertValue(newValue, |
|
|
|
newValue = this.typeConverter.convertValue(newValue, TypeDescriptor.forObject(newValue), |
|
|
|
TypeDescriptor.forObject(newValue), |
|
|
|
this.collectionEntryTypeDescriptor.getElementTypeDescriptor()); |
|
|
|
collectionEntryTypeDescriptor |
|
|
|
|
|
|
|
.getElementTypeDescriptor()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
list.set(index, newValue); |
|
|
|
list.set(this.index, newValue); |
|
|
|
return; |
|
|
|
} |
|
|
|
} else { |
|
|
|
else { |
|
|
|
throw new SpelEvaluationException(getStartPosition(), |
|
|
|
throw new SpelEvaluationException(getStartPosition(), SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, |
|
|
|
SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, |
|
|
|
this.collectionEntryTypeDescriptor.toString()); |
|
|
|
collectionEntryTypeDescriptor.toString()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -318,11 +319,14 @@ public class Indexer extends SpelNodeImpl { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
class StringIndexingLValue implements ValueRef { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private String target; |
|
|
|
private class StringIndexingLValue implements ValueRef { |
|
|
|
private int index; |
|
|
|
|
|
|
|
private TypeDescriptor td; |
|
|
|
private final String target; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final int index; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final TypeDescriptor td; |
|
|
|
|
|
|
|
|
|
|
|
public StringIndexingLValue(String target, int index, TypeDescriptor td) { |
|
|
|
public StringIndexingLValue(String target, int index, TypeDescriptor td) { |
|
|
|
this.target = target; |
|
|
|
this.target = target; |
|
|
|
@ -331,28 +335,25 @@ public class Indexer extends SpelNodeImpl { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public TypedValue getValue() { |
|
|
|
public TypedValue getValue() { |
|
|
|
if (index >= target.length()) { |
|
|
|
if (this.index >= this.target.length()) { |
|
|
|
throw new SpelEvaluationException(getStartPosition(), |
|
|
|
throw new SpelEvaluationException(getStartPosition(), SpelMessage.STRING_INDEX_OUT_OF_BOUNDS, |
|
|
|
SpelMessage.STRING_INDEX_OUT_OF_BOUNDS, |
|
|
|
this.target.length(), index); |
|
|
|
target.length(), index); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
return new TypedValue(String.valueOf(target.charAt(index))); |
|
|
|
return new TypedValue(String.valueOf(this.target.charAt(this.index))); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void setValue(Object newValue) { |
|
|
|
public void setValue(Object newValue) { |
|
|
|
throw new SpelEvaluationException(getStartPosition(), |
|
|
|
throw new SpelEvaluationException(getStartPosition(), SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, |
|
|
|
SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, td.toString()); |
|
|
|
this.td.toString()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public boolean isWritable() { |
|
|
|
public boolean isWritable() { |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
protected ValueRef getValueRef(ExpressionState state) |
|
|
|
protected ValueRef getValueRef(ExpressionState state) throws EvaluationException { |
|
|
|
throws EvaluationException { |
|
|
|
|
|
|
|
TypedValue context = state.getActiveContextObject(); |
|
|
|
TypedValue context = state.getActiveContextObject(); |
|
|
|
Object targetObject = context.getValue(); |
|
|
|
Object targetObject = context.getValue(); |
|
|
|
TypeDescriptor targetObjectTypeDescriptor = context.getTypeDescriptor(); |
|
|
|
TypeDescriptor targetObjectTypeDescriptor = context.getTypeDescriptor(); |
|
|
|
@ -361,18 +362,20 @@ public class Indexer extends SpelNodeImpl { |
|
|
|
|
|
|
|
|
|
|
|
// This first part of the if clause prevents a 'double dereference' of
|
|
|
|
// This first part of the if clause prevents a 'double dereference' of
|
|
|
|
// the property (SPR-5847)
|
|
|
|
// the property (SPR-5847)
|
|
|
|
if (targetObject instanceof Map && (children[0] instanceof PropertyOrFieldReference)) { |
|
|
|
if (targetObject instanceof Map && (this.children[0] instanceof PropertyOrFieldReference)) { |
|
|
|
PropertyOrFieldReference reference = (PropertyOrFieldReference) children[0]; |
|
|
|
PropertyOrFieldReference reference = (PropertyOrFieldReference) this.children[0]; |
|
|
|
index = reference.getName(); |
|
|
|
index = reference.getName(); |
|
|
|
indexValue = new TypedValue(index); |
|
|
|
indexValue = new TypedValue(index); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
// In case the map key is unqualified, we want it evaluated against
|
|
|
|
// In case the map key is unqualified, we want it evaluated against
|
|
|
|
// the root object so temporarily push that on whilst evaluating the key
|
|
|
|
// the root object so temporarily push that on whilst evaluating the key
|
|
|
|
try { |
|
|
|
try { |
|
|
|
state.pushActiveContextObject(state.getRootContextObject()); |
|
|
|
state.pushActiveContextObject(state.getRootContextObject()); |
|
|
|
indexValue = children[0].getValueInternal(state); |
|
|
|
indexValue = this.children[0].getValueInternal(state); |
|
|
|
index = indexValue.getValue(); |
|
|
|
index = indexValue.getValue(); |
|
|
|
} finally { |
|
|
|
} |
|
|
|
|
|
|
|
finally { |
|
|
|
state.popActiveContextObject(); |
|
|
|
state.popActiveContextObject(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -381,69 +384,55 @@ public class Indexer extends SpelNodeImpl { |
|
|
|
if (targetObject instanceof Map) { |
|
|
|
if (targetObject instanceof Map) { |
|
|
|
Object key = index; |
|
|
|
Object key = index; |
|
|
|
if (targetObjectTypeDescriptor.getMapKeyTypeDescriptor() != null) { |
|
|
|
if (targetObjectTypeDescriptor.getMapKeyTypeDescriptor() != null) { |
|
|
|
key = state.convertValue(key, |
|
|
|
key = state.convertValue(key, targetObjectTypeDescriptor.getMapKeyTypeDescriptor()); |
|
|
|
targetObjectTypeDescriptor.getMapKeyTypeDescriptor()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
return new MapIndexingValueRef(state.getTypeConverter(), |
|
|
|
return new MapIndexingValueRef(state.getTypeConverter(), (Map<?, ?>) targetObject, key, |
|
|
|
(Map<?, ?>) targetObject, key, targetObjectTypeDescriptor); |
|
|
|
targetObjectTypeDescriptor); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (targetObject == null) { |
|
|
|
if (targetObject == null) { |
|
|
|
throw new SpelEvaluationException(getStartPosition(), |
|
|
|
throw new SpelEvaluationException(getStartPosition(), SpelMessage.CANNOT_INDEX_INTO_NULL_VALUE); |
|
|
|
SpelMessage.CANNOT_INDEX_INTO_NULL_VALUE); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// if 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
|
|
|
|
// attempt to treat the index value as a number
|
|
|
|
if (targetObject instanceof Collection |
|
|
|
if (targetObject.getClass().isArray() || targetObject instanceof Collection || targetObject instanceof String) { |
|
|
|
|| targetObject.getClass().isArray() |
|
|
|
int idx = (Integer) state.convertValue(index, TypeDescriptor.valueOf(Integer.class)); |
|
|
|
|| targetObject instanceof String) { |
|
|
|
|
|
|
|
int idx = (Integer) state.convertValue(index, |
|
|
|
|
|
|
|
TypeDescriptor.valueOf(Integer.class)); |
|
|
|
|
|
|
|
if (targetObject.getClass().isArray()) { |
|
|
|
if (targetObject.getClass().isArray()) { |
|
|
|
return new ArrayIndexingValueRef(state.getTypeConverter(), |
|
|
|
return new ArrayIndexingValueRef(state.getTypeConverter(), targetObject, idx, targetObjectTypeDescriptor); |
|
|
|
targetObject, idx, targetObjectTypeDescriptor); |
|
|
|
} |
|
|
|
} else if (targetObject instanceof Collection) { |
|
|
|
else if (targetObject instanceof Collection) { |
|
|
|
return new CollectionIndexingValueRef( |
|
|
|
return new CollectionIndexingValueRef((Collection<?>) targetObject, idx, targetObjectTypeDescriptor, |
|
|
|
(Collection<?>) targetObject, idx, |
|
|
|
state.getTypeConverter(), state.getConfiguration().isAutoGrowCollections()); |
|
|
|
targetObjectTypeDescriptor,state.getTypeConverter(), |
|
|
|
} |
|
|
|
state.getConfiguration().isAutoGrowCollections()); |
|
|
|
else if (targetObject instanceof String) { |
|
|
|
} else if (targetObject instanceof String) { |
|
|
|
return new StringIndexingLValue((String) targetObject, idx, targetObjectTypeDescriptor); |
|
|
|
return new StringIndexingLValue((String) targetObject, idx, |
|
|
|
|
|
|
|
targetObjectTypeDescriptor); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Try and treat the index value as a property of the context object
|
|
|
|
// 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
|
|
|
|
// TODO could call the conversion service to convert the value to a String
|
|
|
|
// String
|
|
|
|
|
|
|
|
if (indexValue.getTypeDescriptor().getType() == String.class) { |
|
|
|
if (indexValue.getTypeDescriptor().getType() == String.class) { |
|
|
|
return new PropertyIndexingValueRef(targetObject, |
|
|
|
return new PropertyIndexingValueRef(targetObject, (String) indexValue.getValue(), |
|
|
|
(String) indexValue.getValue(), |
|
|
|
|
|
|
|
state.getEvaluationContext(), targetObjectTypeDescriptor); |
|
|
|
state.getEvaluationContext(), targetObjectTypeDescriptor); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
throw new SpelEvaluationException(getStartPosition(), |
|
|
|
throw new SpelEvaluationException(getStartPosition(), SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, |
|
|
|
SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, |
|
|
|
|
|
|
|
targetObjectTypeDescriptor.toString()); |
|
|
|
targetObjectTypeDescriptor.toString()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Attempt to grow the specified collection so that the specified index is |
|
|
|
* Attempt to grow the specified collection so that the specified index is valid. |
|
|
|
* valid. |
|
|
|
* @param targetType the type of the elements in the collection |
|
|
|
* |
|
|
|
|
|
|
|
* @param elementType the type of the elements in the collection |
|
|
|
|
|
|
|
* @param index the index into the collection that needs to be valid |
|
|
|
* @param index the index into the collection that needs to be valid |
|
|
|
* @param collection the collection to grow with elements |
|
|
|
* @param collection the collection to grow with elements |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private void growCollection(TypeDescriptor targetType, int index, Collection<Object> collection) { |
|
|
|
private void growCollection(TypeDescriptor targetType, int index, Collection<Object> collection) { |
|
|
|
if (targetType.getElementTypeDescriptor() == null) { |
|
|
|
if (targetType.getElementTypeDescriptor() == null) { |
|
|
|
throw new SpelEvaluationException( |
|
|
|
throw new SpelEvaluationException(getStartPosition(), SpelMessage.UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE); |
|
|
|
getStartPosition(), |
|
|
|
|
|
|
|
SpelMessage.UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
TypeDescriptor elementType = targetType.getElementTypeDescriptor(); |
|
|
|
TypeDescriptor elementType = targetType.getElementTypeDescriptor(); |
|
|
|
Object newCollectionElement = null; |
|
|
|
Object newCollectionElement; |
|
|
|
try { |
|
|
|
try { |
|
|
|
int newElements = index - collection.size(); |
|
|
|
int newElements = index - collection.size(); |
|
|
|
while (newElements > 0) { |
|
|
|
while (newElements > 0) { |
|
|
|
@ -451,9 +440,9 @@ public class Indexer extends SpelNodeImpl { |
|
|
|
newElements--; |
|
|
|
newElements--; |
|
|
|
} |
|
|
|
} |
|
|
|
newCollectionElement = elementType.getType().newInstance(); |
|
|
|
newCollectionElement = elementType.getType().newInstance(); |
|
|
|
} catch (Exception ex) { |
|
|
|
} |
|
|
|
throw new SpelEvaluationException(getStartPosition(), ex, |
|
|
|
catch (Exception ex) { |
|
|
|
SpelMessage.UNABLE_TO_GROW_COLLECTION); |
|
|
|
throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.UNABLE_TO_GROW_COLLECTION); |
|
|
|
} |
|
|
|
} |
|
|
|
collection.add(newCollectionElement); |
|
|
|
collection.add(newCollectionElement); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -463,70 +452,70 @@ public class Indexer extends SpelNodeImpl { |
|
|
|
StringBuilder sb = new StringBuilder(); |
|
|
|
StringBuilder sb = new StringBuilder(); |
|
|
|
sb.append("["); |
|
|
|
sb.append("["); |
|
|
|
for (int i = 0; i < getChildCount(); i++) { |
|
|
|
for (int i = 0; i < getChildCount(); i++) { |
|
|
|
if (i > 0) |
|
|
|
if (i > 0) { |
|
|
|
sb.append(","); |
|
|
|
sb.append(","); |
|
|
|
|
|
|
|
} |
|
|
|
sb.append(getChild(i).toStringAST()); |
|
|
|
sb.append(getChild(i).toStringAST()); |
|
|
|
} |
|
|
|
} |
|
|
|
sb.append("]"); |
|
|
|
sb.append("]"); |
|
|
|
return sb.toString(); |
|
|
|
return sb.toString(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void setArrayElement(TypeConverter converter, Object ctx, int idx, |
|
|
|
private void setArrayElement(TypeConverter converter, Object ctx, int idx, Object newValue, Class<?> clazz) |
|
|
|
Object newValue, Class<?> clazz) throws EvaluationException { |
|
|
|
throws EvaluationException { |
|
|
|
Class<?> arrayComponentType = clazz; |
|
|
|
Class<?> arrayComponentType = clazz; |
|
|
|
if (arrayComponentType == Integer.TYPE) { |
|
|
|
if (arrayComponentType == Integer.TYPE) { |
|
|
|
int[] array = (int[]) ctx; |
|
|
|
int[] array = (int[]) ctx; |
|
|
|
checkAccess(array.length, idx); |
|
|
|
checkAccess(array.length, idx); |
|
|
|
array[idx] = (Integer) converter.convertValue(newValue, |
|
|
|
array[idx] = (Integer) converter.convertValue(newValue, TypeDescriptor.forObject(newValue), |
|
|
|
TypeDescriptor.forObject(newValue), |
|
|
|
|
|
|
|
TypeDescriptor.valueOf(Integer.class)); |
|
|
|
TypeDescriptor.valueOf(Integer.class)); |
|
|
|
} else if (arrayComponentType == Boolean.TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (arrayComponentType == Boolean.TYPE) { |
|
|
|
boolean[] array = (boolean[]) ctx; |
|
|
|
boolean[] array = (boolean[]) ctx; |
|
|
|
checkAccess(array.length, idx); |
|
|
|
checkAccess(array.length, idx); |
|
|
|
array[idx] = (Boolean) converter.convertValue(newValue, |
|
|
|
array[idx] = (Boolean) converter.convertValue(newValue, TypeDescriptor.forObject(newValue), |
|
|
|
TypeDescriptor.forObject(newValue), |
|
|
|
|
|
|
|
TypeDescriptor.valueOf(Boolean.class)); |
|
|
|
TypeDescriptor.valueOf(Boolean.class)); |
|
|
|
} else if (arrayComponentType == Character.TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (arrayComponentType == Character.TYPE) { |
|
|
|
char[] array = (char[]) ctx; |
|
|
|
char[] array = (char[]) ctx; |
|
|
|
checkAccess(array.length, idx); |
|
|
|
checkAccess(array.length, idx); |
|
|
|
array[idx] = (Character) converter.convertValue(newValue, |
|
|
|
array[idx] = (Character) converter.convertValue(newValue, TypeDescriptor.forObject(newValue), |
|
|
|
TypeDescriptor.forObject(newValue), |
|
|
|
|
|
|
|
TypeDescriptor.valueOf(Character.class)); |
|
|
|
TypeDescriptor.valueOf(Character.class)); |
|
|
|
} else if (arrayComponentType == Long.TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (arrayComponentType == Long.TYPE) { |
|
|
|
long[] array = (long[]) ctx; |
|
|
|
long[] array = (long[]) ctx; |
|
|
|
checkAccess(array.length, idx); |
|
|
|
checkAccess(array.length, idx); |
|
|
|
array[idx] = (Long) converter.convertValue(newValue, |
|
|
|
array[idx] = (Long) converter.convertValue(newValue, TypeDescriptor.forObject(newValue), |
|
|
|
TypeDescriptor.forObject(newValue), |
|
|
|
|
|
|
|
TypeDescriptor.valueOf(Long.class)); |
|
|
|
TypeDescriptor.valueOf(Long.class)); |
|
|
|
} else if (arrayComponentType == Short.TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (arrayComponentType == Short.TYPE) { |
|
|
|
short[] array = (short[]) ctx; |
|
|
|
short[] array = (short[]) ctx; |
|
|
|
checkAccess(array.length, idx); |
|
|
|
checkAccess(array.length, idx); |
|
|
|
array[idx] = (Short) converter.convertValue(newValue, |
|
|
|
array[idx] = (Short) converter.convertValue(newValue, TypeDescriptor.forObject(newValue), |
|
|
|
TypeDescriptor.forObject(newValue), |
|
|
|
|
|
|
|
TypeDescriptor.valueOf(Short.class)); |
|
|
|
TypeDescriptor.valueOf(Short.class)); |
|
|
|
} else if (arrayComponentType == Double.TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (arrayComponentType == Double.TYPE) { |
|
|
|
double[] array = (double[]) ctx; |
|
|
|
double[] array = (double[]) ctx; |
|
|
|
checkAccess(array.length, idx); |
|
|
|
checkAccess(array.length, idx); |
|
|
|
array[idx] = (Double) converter.convertValue(newValue, |
|
|
|
array[idx] = (Double) converter.convertValue(newValue, TypeDescriptor.forObject(newValue), |
|
|
|
TypeDescriptor.forObject(newValue), |
|
|
|
|
|
|
|
TypeDescriptor.valueOf(Double.class)); |
|
|
|
TypeDescriptor.valueOf(Double.class)); |
|
|
|
} else if (arrayComponentType == Float.TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (arrayComponentType == Float.TYPE) { |
|
|
|
float[] array = (float[]) ctx; |
|
|
|
float[] array = (float[]) ctx; |
|
|
|
checkAccess(array.length, idx); |
|
|
|
checkAccess(array.length, idx); |
|
|
|
array[idx] = (Float) converter.convertValue(newValue, |
|
|
|
array[idx] = (Float) converter.convertValue(newValue, TypeDescriptor.forObject(newValue), |
|
|
|
TypeDescriptor.forObject(newValue), |
|
|
|
|
|
|
|
TypeDescriptor.valueOf(Float.class)); |
|
|
|
TypeDescriptor.valueOf(Float.class)); |
|
|
|
} else if (arrayComponentType == Byte.TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (arrayComponentType == Byte.TYPE) { |
|
|
|
byte[] array = (byte[]) ctx; |
|
|
|
byte[] array = (byte[]) ctx; |
|
|
|
checkAccess(array.length, idx); |
|
|
|
checkAccess(array.length, idx); |
|
|
|
array[idx] = (Byte) converter.convertValue(newValue, |
|
|
|
array[idx] = (Byte) converter.convertValue(newValue, TypeDescriptor.forObject(newValue), |
|
|
|
TypeDescriptor.forObject(newValue), |
|
|
|
|
|
|
|
TypeDescriptor.valueOf(Byte.class)); |
|
|
|
TypeDescriptor.valueOf(Byte.class)); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
Object[] array = (Object[]) ctx; |
|
|
|
Object[] array = (Object[]) ctx; |
|
|
|
checkAccess(array.length, idx); |
|
|
|
checkAccess(array.length, idx); |
|
|
|
array[idx] = converter.convertValue(newValue, |
|
|
|
array[idx] = converter.convertValue(newValue, TypeDescriptor.forObject(newValue), |
|
|
|
TypeDescriptor.forObject(newValue), |
|
|
|
|
|
|
|
TypeDescriptor.valueOf(clazz)); |
|
|
|
TypeDescriptor.valueOf(clazz)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -537,35 +526,43 @@ public class Indexer extends SpelNodeImpl { |
|
|
|
int[] array = (int[]) ctx; |
|
|
|
int[] array = (int[]) ctx; |
|
|
|
checkAccess(array.length, idx); |
|
|
|
checkAccess(array.length, idx); |
|
|
|
return array[idx]; |
|
|
|
return array[idx]; |
|
|
|
} else if (arrayComponentType == Boolean.TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (arrayComponentType == Boolean.TYPE) { |
|
|
|
boolean[] array = (boolean[]) ctx; |
|
|
|
boolean[] array = (boolean[]) ctx; |
|
|
|
checkAccess(array.length, idx); |
|
|
|
checkAccess(array.length, idx); |
|
|
|
return array[idx]; |
|
|
|
return array[idx]; |
|
|
|
} else if (arrayComponentType == Character.TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (arrayComponentType == Character.TYPE) { |
|
|
|
char[] array = (char[]) ctx; |
|
|
|
char[] array = (char[]) ctx; |
|
|
|
checkAccess(array.length, idx); |
|
|
|
checkAccess(array.length, idx); |
|
|
|
return array[idx]; |
|
|
|
return array[idx]; |
|
|
|
} else if (arrayComponentType == Long.TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (arrayComponentType == Long.TYPE) { |
|
|
|
long[] array = (long[]) ctx; |
|
|
|
long[] array = (long[]) ctx; |
|
|
|
checkAccess(array.length, idx); |
|
|
|
checkAccess(array.length, idx); |
|
|
|
return array[idx]; |
|
|
|
return array[idx]; |
|
|
|
} else if (arrayComponentType == Short.TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (arrayComponentType == Short.TYPE) { |
|
|
|
short[] array = (short[]) ctx; |
|
|
|
short[] array = (short[]) ctx; |
|
|
|
checkAccess(array.length, idx); |
|
|
|
checkAccess(array.length, idx); |
|
|
|
return array[idx]; |
|
|
|
return array[idx]; |
|
|
|
} else if (arrayComponentType == Double.TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (arrayComponentType == Double.TYPE) { |
|
|
|
double[] array = (double[]) ctx; |
|
|
|
double[] array = (double[]) ctx; |
|
|
|
checkAccess(array.length, idx); |
|
|
|
checkAccess(array.length, idx); |
|
|
|
return array[idx]; |
|
|
|
return array[idx]; |
|
|
|
} else if (arrayComponentType == Float.TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (arrayComponentType == Float.TYPE) { |
|
|
|
float[] array = (float[]) ctx; |
|
|
|
float[] array = (float[]) ctx; |
|
|
|
checkAccess(array.length, idx); |
|
|
|
checkAccess(array.length, idx); |
|
|
|
return array[idx]; |
|
|
|
return array[idx]; |
|
|
|
} else if (arrayComponentType == Byte.TYPE) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (arrayComponentType == Byte.TYPE) { |
|
|
|
byte[] array = (byte[]) ctx; |
|
|
|
byte[] array = (byte[]) ctx; |
|
|
|
checkAccess(array.length, idx); |
|
|
|
checkAccess(array.length, idx); |
|
|
|
return array[idx]; |
|
|
|
return array[idx]; |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
Object[] array = (Object[]) ctx; |
|
|
|
Object[] array = (Object[]) ctx; |
|
|
|
checkAccess(array.length, idx); |
|
|
|
checkAccess(array.length, idx); |
|
|
|
return array[idx]; |
|
|
|
return array[idx]; |
|
|
|
@ -574,9 +571,9 @@ public class Indexer extends SpelNodeImpl { |
|
|
|
|
|
|
|
|
|
|
|
private void checkAccess(int arrayLength, int index) throws SpelEvaluationException { |
|
|
|
private void checkAccess(int arrayLength, int index) throws SpelEvaluationException { |
|
|
|
if (index > arrayLength) { |
|
|
|
if (index > arrayLength) { |
|
|
|
throw new SpelEvaluationException(getStartPosition(), |
|
|
|
throw new SpelEvaluationException(getStartPosition(), SpelMessage.ARRAY_INDEX_OUT_OF_BOUNDS, |
|
|
|
SpelMessage.ARRAY_INDEX_OUT_OF_BOUNDS, arrayLength, index); |
|
|
|
arrayLength, index); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|