Object targetObject = contextObject.getValue();
TypeDescriptor targetObjectTypeDescriptor = contextObject.getTypeDescriptor();
TypedValue index = children[0].getValueInternal(state);
if (targetObject == null) {
throw new SpelEvaluationException(SpelMessage.CANNOT_INDEX_INTO_NULL_VALUE);
}
// Indexing into a Map
if (targetObject instanceof Map) {
Map map = (Map) targetObject;
Object key = index.getValue();
if (targetObjectTypeDescriptor.getMapKeyTypeDescriptor() != null) {
key = state.convertValue(index, targetObjectTypeDescriptor.getMapKeyTypeDescriptor());
}
if (targetObjectTypeDescriptor.getMapValueTypeDescriptor() != null) {
newValue = state.convertValue(newValue, targetObjectTypeDescriptor.getMapValueTypeDescriptor());
}
map.put(key, newValue);
return;
}
if (targetObjectTypeDescriptor.isArray()) {
int idx = (Integer)state.convertValue(index, TypeDescriptor.valueOf(Integer.class));
setArrayElement(state, contextObject.getValue(), idx, newValue, targetObjectTypeDescriptor.getElementTypeDescriptor().getType());
return;
}
else if (targetObject instanceof Collection) {
int idx = (Integer) state.convertValue(index, TypeDescriptor.valueOf(Integer.class));
Collection c = (Collection) targetObject;
if (idx >= c.size()) {
if (!growCollection(state, targetObjectTypeDescriptor, idx, c)) {
throw new SpelEvaluationException(getStartPosition(),SpelMessage.COLLECTION_INDEX_OUT_OF_BOUNDS, c.size(), idx);
}
}
if (targetObject instanceof List) {
List list = (List) targetObject;
if (targetObjectTypeDescriptor.getElementTypeDescriptor() != null) {
newValue = state.convertValue(newValue, targetObjectTypeDescriptor.getElementTypeDescriptor());
}
list.set(idx, newValue);
return;
}
else {
throw new SpelEvaluationException(getStartPosition(),SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, targetObjectTypeDescriptor.toString());
}
}
// 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 (index.getTypeDescriptor().getType() == String.class) {
Class<?> contextObjectClass = getObjectClass(contextObject.getValue());
String name = (String)index.getValue();
EvaluationContext eContext = state.getEvaluationContext();
try {
if (cachedWriteName!=null && cachedWriteName.equals(name) && cachedWriteTargetType!=null && cachedWriteTargetType.equals(contextObjectClass)) {
// it is OK to use the cached accessor
cachedWriteAccessor.write(eContext, targetObject, name,newValue);
return;
}
List<PropertyAccessor> accessorsToTry = AstUtils.getPropertyAccessorsToTry(contextObjectClass, state);
if (accessorsToTry != null) {
for (PropertyAccessor accessor : accessorsToTry) {
if (accessor.canWrite(eContext, contextObject.getValue(), name)) {
this.cachedWriteName = name;
this.cachedWriteTargetType = contextObjectClass;
this.cachedWriteAccessor = accessor;
accessor.write(eContext, contextObject.getValue(), name, newValue);
return;
}
}
}
} catch (AccessException ae) {
throw new SpelEvaluationException(getStartPosition(), ae, SpelMessage.EXCEPTION_DURING_PROPERTY_WRITE,
name, ae.getMessage());
}
}
throw new SpelEvaluationException(getStartPosition(),SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, targetObjectTypeDescriptor.toString());
}