private TypedValue CreateArray(ExpressionState state) { // First child gives us the array type which will either be a primitive or reference type var intendedArrayType = GetChild(0).GetValue(state); if (intendedArrayType is not string) { throw new SpelEvaluationException( GetChild(0).StartPosition, SpelMessage.TYPE_NAME_EXPECTED_FOR_ARRAY_CONSTRUCTION, FormatHelper.FormatClassNameForMessage(intendedArrayType?.GetType())); } var type = (string)intendedArrayType; Type componentType; var arrayTypeCode = SpelTypeCode.ForName(type); if (arrayTypeCode == SpelTypeCode.OBJECT) { componentType = state.FindType(type); } else { componentType = arrayTypeCode.Type; } object newArray; if (!HasInitializer) { // Confirm all dimensions were specified (for example [3][][5] is missing the 2nd dimension) if (_dimensions != null) { foreach (var dimension in _dimensions) { if (dimension == null) { throw new SpelEvaluationException(StartPosition, SpelMessage.MISSING_ARRAY_DIMENSION); } } } else { throw new SpelEvaluationException(StartPosition, SpelMessage.MISSING_ARRAY_DIMENSION); } var typeConverter = state.EvaluationContext.TypeConverter; // Shortcut for 1 dimensional if (_dimensions.Length == 1) { var o = _dimensions[0].GetTypedValue(state); var arraySize = ExpressionUtils.ToInt(typeConverter, o); newArray = Array.CreateInstance(componentType, arraySize); } else { // Multi-dimensional - hold onto your hat! var dims = new int[_dimensions.Length]; for (var d = 0; d < _dimensions.Length; d++) { var o = _dimensions[d].GetTypedValue(state); dims[d] = ExpressionUtils.ToInt(typeConverter, o); } newArray = Array.CreateInstance(componentType, dims); } } else { // There is an initializer if (_dimensions == null || _dimensions.Length > 1) { // There is an initializer but this is a multi-dimensional array (e.g. new int[][]{{1,2},{3,4}}) - this // is not currently supported throw new SpelEvaluationException(StartPosition, SpelMessage.MULTIDIM_ARRAY_INITIALIZER_NOT_SUPPORTED); } var typeConverter = state.EvaluationContext.TypeConverter; var initializer = (InlineList)GetChild(1); // If a dimension was specified, check it matches the initializer length if (_dimensions[0] != null) { var dValue = _dimensions[0].GetTypedValue(state); var i = ExpressionUtils.ToInt(typeConverter, dValue); if (i != initializer.ChildCount) { throw new SpelEvaluationException(StartPosition, SpelMessage.INITIALIZER_LENGTH_INCORRECT); } } // Build the array and populate it var arraySize = initializer.ChildCount; newArray = Array.CreateInstance(componentType, arraySize); if (arrayTypeCode == SpelTypeCode.OBJECT) { PopulateReferenceTypeArray(state, newArray, typeConverter, initializer, componentType); } else if (arrayTypeCode == SpelTypeCode.BOOLEAN) { PopulateBooleanArray(state, newArray, typeConverter, initializer); } else if (arrayTypeCode == SpelTypeCode.BYTE) { PopulateByteArray(state, newArray, typeConverter, initializer); } else if (arrayTypeCode == SpelTypeCode.SBYTE) { PopulateSByteArray(state, newArray, typeConverter, initializer); } else if (arrayTypeCode == SpelTypeCode.CHAR) { PopulateCharArray(state, newArray, typeConverter, initializer); } else if (arrayTypeCode == SpelTypeCode.DOUBLE) { PopulateDoubleArray(state, newArray, typeConverter, initializer); } else if (arrayTypeCode == SpelTypeCode.FLOAT) { PopulateFloatArray(state, newArray, typeConverter, initializer); } else if (arrayTypeCode == SpelTypeCode.INT) { PopulateIntArray(state, newArray, typeConverter, initializer); } else if (arrayTypeCode == SpelTypeCode.UINT) { PopulateUIntArray(state, newArray, typeConverter, initializer); } else if (arrayTypeCode == SpelTypeCode.LONG) { PopulateLongArray(state, newArray, typeConverter, initializer); } else if (arrayTypeCode == SpelTypeCode.ULONG) { PopulateULongArray(state, newArray, typeConverter, initializer); } else if (arrayTypeCode == SpelTypeCode.SHORT) { PopulateShortArray(state, newArray, typeConverter, initializer); } else if (arrayTypeCode == SpelTypeCode.USHORT) { PopulateUShortArray(state, newArray, typeConverter, initializer); } else { throw new InvalidOperationException(arrayTypeCode.Name); } } return(new TypedValue(newArray)); }
private ITypedValue CreateNewInstance(ExpressionState state) { var arguments = new object[ChildCount - 1]; var argumentTypes = new List <Type>(ChildCount - 1); for (var i = 0; i < arguments.Length; i++) { var childValue = _children[i + 1].GetValueInternal(state); var value = childValue.Value; arguments[i] = value; var valueType = value?.GetType(); argumentTypes.Add(valueType); } var executorToUse = _cachedExecutor; if (executorToUse != null) { try { return(executorToUse.Execute(state.EvaluationContext, arguments)); } catch (AccessException ex) { // Two reasons this can occur: // 1. the method invoked actually threw a real exception // 2. the method invoked was not passed the arguments it expected and has become 'stale' // In the first case we should not retry, in the second case we should see if there is a // better suited method. // To determine which situation it is, the AccessException will contain a cause. // If the cause is an InvocationTargetException, a user exception was thrown inside the constructor. // Otherwise the constructor could not be invoked. if (ex.InnerException is TargetInvocationException) { // User exception was the root cause - exit now var rootCause = ex.InnerException.InnerException; if (rootCause is SystemException) { throw rootCause; } var name = (string)_children[0].GetValueInternal(state).Value; throw new SpelEvaluationException( StartPosition, rootCause, SpelMessage.CONSTRUCTOR_INVOCATION_PROBLEM, name, FormatHelper.FormatMethodForMessage(string.Empty, argumentTypes)); } // At this point we know it wasn't a user problem so worth a retry if a better candidate can be found _cachedExecutor = null; } } // Either there was no accessor or it no longer exists var typeName = (string)_children[0].GetValueInternal(state).Value; if (typeName == null) { throw new InvalidOperationException("No type name"); } executorToUse = FindExecutorForConstructor(typeName, argumentTypes, state); try { _cachedExecutor = executorToUse; if (executorToUse is ReflectiveConstructorExecutor executor) { _exitTypeDescriptor = CodeFlow.ToDescriptor(executor.Constructor.DeclaringType); } return(executorToUse.Execute(state.EvaluationContext, arguments)); } catch (AccessException ex) { throw new SpelEvaluationException( StartPosition, ex, SpelMessage.CONSTRUCTOR_INVOCATION_PROBLEM, typeName, FormatHelper.FormatMethodForMessage(string.Empty, argumentTypes)); } }
private void WriteProperty(ITypedValue contextObject, IEvaluationContext evalContext, string name, object newValue) { if (contextObject.Value == null && _nullSafe) { return; } if (contextObject.Value == null) { throw new SpelEvaluationException(StartPosition, SpelMessage.PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL, name); } var accessorToUse = _cachedWriteAccessor; if (accessorToUse != null) { if (evalContext.PropertyAccessors.Contains(accessorToUse)) { try { accessorToUse.Write(evalContext, contextObject.Value, name, newValue); return; } catch (Exception ex) { // This is OK - it may have gone stale due to a class change, // let's try to get a new one and call it before giving up... } } _cachedWriteAccessor = null; } var accessorsToTry = GetPropertyAccessorsToTry(contextObject.Value, evalContext.PropertyAccessors); try { foreach (var accessor in accessorsToTry) { if (accessor.CanWrite(evalContext, contextObject.Value, name)) { _cachedWriteAccessor = accessor; accessor.Write(evalContext, contextObject.Value, name, newValue); return; } } } catch (AccessException ex) { throw new SpelEvaluationException(StartPosition, ex, SpelMessage.EXCEPTION_DURING_PROPERTY_WRITE, name, ex.Message); } throw new SpelEvaluationException(StartPosition, SpelMessage.PROPERTY_OR_FIELD_NOT_WRITABLE, name, FormatHelper.FormatClassNameForMessage(GetObjectType(contextObject.Value))); }
private void ThrowIfNotNullSafe(IList <Type> argumentTypes) { if (!_nullSafe) { throw new SpelEvaluationException(StartPosition, SpelMessage.METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED, FormatHelper.FormatMethodForMessage(_name, argumentTypes)); } }
private ITypedValue ReadProperty(ITypedValue contextObject, IEvaluationContext evalContext, string name) { var targetObject = contextObject.Value; if (targetObject == null && _nullSafe) { return(TypedValue.NULL); } var accessorToUse = _cachedReadAccessor; if (accessorToUse != null) { if (evalContext.PropertyAccessors.Contains(accessorToUse)) { try { return(accessorToUse.Read(evalContext, contextObject.Value, name)); } catch (Exception ex) { // This is OK - it may have gone stale due to a class change, // let's try to get a new one and call it before giving up... } } _cachedReadAccessor = null; } var accessorsToTry = GetPropertyAccessorsToTry(contextObject.Value, evalContext.PropertyAccessors); // Go through the accessors that may be able to resolve it. If they are a cacheable accessor then // get the accessor and use it. If they are not cacheable but report they can read the property // then ask them to read it try { foreach (var acc in accessorsToTry) { var accessor = acc; if (accessor.CanRead(evalContext, contextObject.Value, name)) { if (accessor is ReflectivePropertyAccessor) { accessor = ((ReflectivePropertyAccessor)accessor).CreateOptimalAccessor(evalContext, contextObject.Value, name); } _cachedReadAccessor = accessor; return(accessor.Read(evalContext, contextObject.Value, name)); } } } catch (Exception ex) { throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_DURING_PROPERTY_READ, name, ex.Message); } if (contextObject.Value == null) { throw new SpelEvaluationException(SpelMessage.PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL, name); } else { throw new SpelEvaluationException(StartPosition, SpelMessage.PROPERTY_OR_FIELD_NOT_READABLE, _name, FormatHelper.FormatClassNameForMessage(GetObjectType(contextObject.Value))); } }