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