예제 #1
0
        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);
        }
예제 #2
0
        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);
        }