protected internal override IValueRef GetValueRef(ExpressionState state) { if (ChildCount == 1) { return(_children[0].GetValueRef(state)); } var nextNode = _children[0]; try { var result = nextNode.GetValueInternal(state); var cc = ChildCount; for (var i = 1; i < cc - 1; i++) { try { state.PushActiveContextObject(result); nextNode = _children[i]; result = nextNode.GetValueInternal(state); } finally { state.PopActiveContextObject(); } } try { state.PushActiveContextObject(result); nextNode = _children[cc - 1]; return(nextNode.GetValueRef(state)); } finally { state.PopActiveContextObject(); } } catch (SpelEvaluationException ex) { // Correct the position for the error before re-throwing ex.Position = nextNode.StartPosition; throw; } }
private object[] GetArguments(ExpressionState state) { var arguments = new object[ChildCount]; for (var i = 0; i < arguments.Length; i++) { // Make the root object the active context again for evaluating the parameter expressions try { state.PushActiveContextObject(state.GetScopeRootContextObject()); arguments[i] = _children[i].GetValueInternal(state).Value; } finally { state.PopActiveContextObject(); } } return(arguments); }
protected internal override IValueRef GetValueRef(ExpressionState state) { var op = state.GetActiveContextObject(); var operand = op.Value; var selectionCriteria = _children[0]; if (operand is System.Collections.IDictionary mapdata) { // Don't lose generic info for the new map var result = new Dictionary <object, object>(); object lastKey = null; foreach (DictionaryEntry entry in mapdata) { try { var kvPair = new TypedValue(entry); state.PushActiveContextObject(kvPair); state.EnterScope(); var val = selectionCriteria.GetValueInternal(state).Value; if (val is bool boolean) { if (boolean) { if (_variant == FIRST) { result[entry.Key] = entry.Value; return(new TypedValueHolderValueRef(new TypedValue(result), this)); } result[entry.Key] = entry.Value; lastKey = entry.Key; } } else { throw new SpelEvaluationException(selectionCriteria.StartPosition, SpelMessage.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN); } } finally { state.PopActiveContextObject(); state.ExitScope(); } } if ((_variant == FIRST || _variant == LAST) && result.Count == 0) { return(new TypedValueHolderValueRef(new TypedValue(null), this)); } if (_variant == LAST) { var resultMap = new Dictionary <object, object>(); result.TryGetValue(lastKey, out var lastValue); resultMap[lastKey] = lastValue; return(new TypedValueHolderValueRef(new TypedValue(resultMap), this)); } return(new TypedValueHolderValueRef(new TypedValue(result), this)); } if (operand is IEnumerable) { var operandAsArray = operand as Array; var data = operand as IEnumerable; var result = new List <object>(); var index = 0; foreach (var element in data) { try { state.PushActiveContextObject(new TypedValue(element)); state.EnterScope("index", index); var val = selectionCriteria.GetValueInternal(state).Value; if (val is bool boolean) { if (boolean) { if (_variant == FIRST) { return(new TypedValueHolderValueRef(new TypedValue(element), this)); } result.Add(element); } } else { throw new SpelEvaluationException(selectionCriteria.StartPosition, SpelMessage.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN); } index++; } finally { state.ExitScope(); state.PopActiveContextObject(); } } if ((_variant == FIRST || _variant == LAST) && result.Count == 0) { return(NullValueRef.INSTANCE); } if (_variant == LAST) { var lastElem = result == null || result.Count == 0 ? null : result[result.Count - 1]; return(new TypedValueHolderValueRef(new TypedValue(lastElem), this)); } if (operand is IEnumerable && operandAsArray == null) { return(new TypedValueHolderValueRef(new TypedValue(result), this)); } // Array if (operandAsArray != null) { Type elementType = null; var typeDesc = op.TypeDescriptor; if (typeDesc != null) { elementType = ReflectionHelper.GetElementTypeDescriptor(typeDesc); } if (elementType == null) { throw new InvalidOperationException("Unresolvable element type"); } var resultArray = Array.CreateInstance(elementType, result.Count); Array.Copy(result.ToArray(), 0, resultArray, 0, result.Count); return(new TypedValueHolderValueRef(new TypedValue(resultArray), this)); } } if (operand == null) { if (_nullSafe) { return(NullValueRef.INSTANCE); } throw new SpelEvaluationException(StartPosition, SpelMessage.INVALID_TYPE_FOR_SELECTION, "null"); } throw new SpelEvaluationException(StartPosition, SpelMessage.INVALID_TYPE_FOR_SELECTION, operand.GetType().FullName); }
protected internal override IValueRef GetValueRef(ExpressionState state) { var context = state.GetActiveContextObject(); var target = context.Value; var targetDescriptor = context.TypeDescriptor; ITypedValue indexValue; object index; // This first part of the if clause prevents a 'double dereference' of the property (SPR-5847) if (target is System.Collections.IDictionary && (_children[0] is PropertyOrFieldReference reference1)) { var reference = reference1; index = reference.Name; 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.RootContextObject); indexValue = _children[0].GetValueInternal(state); index = indexValue.Value; if (index == null) { throw new InvalidOperationException("No index"); } } finally { state.PopActiveContextObject(); } } // Raise a proper exception in case of a null target if (target == null) { throw new SpelEvaluationException(StartPosition, SpelMessage.CANNOT_INDEX_INTO_NULL_VALUE); } // At this point, we need a TypeDescriptor for a non-null target object if (targetDescriptor == null) { throw new InvalidOperationException("No type descriptor"); } // Indexing into a Map if (target is System.Collections.IDictionary) { var key = index; var mapkeyType = ReflectionHelper.GetMapKeyTypeDescriptor(targetDescriptor); if (mapkeyType != null) { key = state.ConvertValue(key, mapkeyType); } _indexedType = IndexedType.MAP; return(new MapIndexingValueRef(this, state.TypeConverter, (IDictionary)target, key, targetDescriptor)); } // If the object is something that looks indexable by an integer, // attempt to treat the index value as a number if (target is Array || target is IList || target is string) { var idx = (int)state.ConvertValue(index, typeof(int)); if (target is Array) { _indexedType = IndexedType.ARRAY; return(new ArrayIndexingValueRef(this, state.TypeConverter, target, idx, targetDescriptor)); } else if (target is IList list) { _indexedType = IndexedType.LIST; return(new CollectionIndexingValueRef(this, list, idx, targetDescriptor, state.TypeConverter, state.Configuration.AutoGrowCollections, state.Configuration.MaximumAutoGrowSize)); } else { _indexedType = IndexedType.STRING; return(new StringIndexingLValue(this, (string)target, idx, targetDescriptor)); } } // Try and treat the index value as a property of the context object // Could call the conversion service to convert the value to a String var valueType = indexValue.TypeDescriptor; if (valueType != null && typeof(string) == valueType) { _indexedType = IndexedType.OBJECT; return(new PropertyIndexingValueRef(this, target, (string)index, state.EvaluationContext, targetDescriptor)); } throw new SpelEvaluationException(StartPosition, SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE, targetDescriptor); }
protected internal override IValueRef GetValueRef(ExpressionState state) { var op = state.GetActiveContextObject(); var operand = op.Value; var operandAsArray = operand as Array; // TypeDescriptor operandTypeDescriptor = op.getTypeDescriptor(); // When the input is a map, we push a special context object on the stack // before calling the specified operation. This special context object // has two fields 'key' and 'value' that refer to the map entries key // and value, and they can be referenced in the operation // eg. {'a':'y','b':'n'}.![value=='y'?key:null]" == ['a', null] if (operand is IDictionary) { var mapData = (IDictionary)operand; var result = new List <object>(); foreach (var entry in mapData) { try { state.PushActiveContextObject(new TypedValue(entry)); state.EnterScope(); result.Add(_children[0].GetValueInternal(state).Value); } finally { state.PopActiveContextObject(); state.ExitScope(); } } return(new TypedValueHolderValueRef(new TypedValue(result), this)); // TODO unable to build correct type descriptor } if (operand is IEnumerable) { var data = operand as IEnumerable; var result = new List <object>(); Type arrayElementType = null; foreach (var element in data) { try { state.PushActiveContextObject(new TypedValue(element)); state.EnterScope("index", result.Count); var value = _children[0].GetValueInternal(state).Value; if (value != null && operandAsArray != null) { arrayElementType = DetermineCommonType(arrayElementType, value.GetType()); } result.Add(value); } finally { state.ExitScope(); state.PopActiveContextObject(); } } if (operandAsArray != null) { if (arrayElementType == null) { arrayElementType = typeof(object); } var resultArray = Array.CreateInstance(arrayElementType, result.Count); Array.Copy(result.ToArray(), 0, resultArray, 0, result.Count); return(new TypedValueHolderValueRef(new TypedValue(resultArray), this)); } return(new TypedValueHolderValueRef(new TypedValue(result), this)); } if (operand == null) { if (_nullSafe) { return(NullValueRef.INSTANCE); } throw new SpelEvaluationException(StartPosition, SpelMessage.PROJECTION_NOT_SUPPORTED_ON_TYPE, "null"); } throw new SpelEvaluationException(StartPosition, SpelMessage.PROJECTION_NOT_SUPPORTED_ON_TYPE, operand.GetType().FullName); }