}
}
@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());
}
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());