private ITypedValue GetValueInternal(IEvaluationContext evaluationContext, object value, Type targetType, object[] arguments) { var argumentTypes = GetArgumentTypes(arguments); if (value == null) { ThrowIfNotNullSafe(argumentTypes); return(TypedValue.NULL); } var executorToUse = GetCachedExecutor(evaluationContext, value, targetType, argumentTypes); if (executorToUse != null) { try { return(executorToUse.Execute(evaluationContext, value, 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 the situation, the AccessException will contain a cause. // If the cause is an InvocationTargetException, a user exception was // thrown inside the method. Otherwise the method could not be invoked. ThrowSimpleExceptionIfPossible(value, ex); // 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 existed executorToUse = FindAccessorForMethod(argumentTypes, value, evaluationContext); _cachedExecutor = new CachedMethodExecutor(executorToUse, value is Type type ? type : null, targetType, argumentTypes); try { return(executorToUse.Execute(evaluationContext, value, arguments)); } catch (AccessException ex) { // Same unwrapping exception handling as above in above catch block ThrowSimpleExceptionIfPossible(value, ex); throw new SpelEvaluationException(StartPosition, ex, SpelMessage.EXCEPTION_DURING_METHOD_INVOCATION, _name, value.GetType().FullName, ex.Message); } }
private IMethodExecutor GetCachedExecutor(IEvaluationContext evaluationContext, object value, Type target, IList <Type> argumentTypes) { var methodResolvers = evaluationContext.MethodResolvers; if (methodResolvers.Count != 1 || methodResolvers[0] is not ReflectiveMethodResolver) { // Not a default ReflectiveMethodResolver - don't know whether caching is valid return(null); } var executorToCheck = _cachedExecutor; if (executorToCheck != null && executorToCheck.IsSuitable(value, target, argumentTypes)) { return(executorToCheck.Get()); } _cachedExecutor = null; return(null); }