public MethodExecutor resolve( EvaluationContext context, Object targetObject, String name, Class<?>[] arguments) throws AccessException { if (name.equals("hasRole")) { return new HasRoleExecutor(context.getTypeConverter()); } return null; }
/** * Determines if there is a type converter available in the specified context and attempts to use * it to convert the supplied value to the specified type. Throws an exception if conversion is * not possible. * * @param context the evaluation context that may define a type converter * @param typedValue the value to convert and a type descriptor describing it * @param targetType the type to attempt conversion to * @return the converted value * @throws EvaluationException if there is a problem during conversion or conversion of the value * to the specified type is not supported */ @SuppressWarnings("unchecked") public static <T> T convertTypedValue( EvaluationContext context, TypedValue typedValue, Class<T> targetType) { Object value = typedValue.getValue(); if ((targetType == null) || (value != null && ClassUtils.isAssignableValue(targetType, value))) { return (T) value; } if (context != null) { return (T) context .getTypeConverter() .convertValue( value, typedValue.getTypeDescriptor(), TypeDescriptor.valueOf(targetType)); } throw new EvaluationException( "Cannot convert value '" + value + "' to type '" + targetType.getName() + "'"); }
/** * Locate a constructor on the type. There are three kinds of match that might occur: * * <ol> * <li>An exact match where the types of the arguments match the types of the constructor * <li>An in-exact match where the types we are looking for are subtypes of those defined on the * constructor * <li>A match where we are able to convert the arguments into those expected by the * constructor, according to the registered type converter. * </ol> */ @Override public ConstructorExecutor resolve( EvaluationContext context, String typename, List<TypeDescriptor> argumentTypes) throws AccessException { try { TypeConverter typeConverter = context.getTypeConverter(); Class<?> type = context.getTypeLocator().findType(typename); Constructor<?>[] ctors = type.getConstructors(); Arrays.sort( ctors, new Comparator<Constructor<?>>() { @Override public int compare(Constructor<?> c1, Constructor<?> c2) { int c1pl = c1.getParameterTypes().length; int c2pl = c2.getParameterTypes().length; return (new Integer(c1pl)).compareTo(c2pl); } }); Constructor<?> closeMatch = null; for (Constructor<?> ctor : ctors) { Class<?>[] paramTypes = ctor.getParameterTypes(); List<TypeDescriptor> paramDescriptors = new ArrayList<TypeDescriptor>(paramTypes.length); for (int i = 0; i < paramTypes.length; i++) { paramDescriptors.add(new TypeDescriptor(new MethodParameter(ctor, i))); } ReflectionHelper.ArgumentsMatchInfo matchInfo = null; if (ctor.isVarArgs() && argumentTypes.size() >= paramTypes.length - 1) { // *sigh* complicated // Basically.. we have to have all parameters match up until the varargs one, then the // rest of what is // being provided should be // the same type whilst the final argument to the method must be an array of that (oh, how // easy...not) - // or the final parameter // we are supplied does match exactly (it is an array already). matchInfo = ReflectionHelper.compareArgumentsVarargs( paramDescriptors, argumentTypes, typeConverter); } else if (paramTypes.length == argumentTypes.size()) { // worth a closer look matchInfo = ReflectionHelper.compareArguments(paramDescriptors, argumentTypes, typeConverter); } if (matchInfo != null) { if (matchInfo.isExactMatch()) { return new ReflectiveConstructorExecutor(ctor); } else if (matchInfo.isCloseMatch() || matchInfo.isMatchRequiringConversion()) { closeMatch = ctor; } } } return (closeMatch != null ? new ReflectiveConstructorExecutor(closeMatch) : null); } catch (EvaluationException ex) { throw new AccessException("Failed to resolve constructor", ex); } }
@Override public TypeConverter getTypeConverter() { return delegate.getTypeConverter(); }
@Override public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { if (target == null) { throw new AccessException("Cannot write property on null target"); } Class<?> type = (target instanceof Class ? (Class<?>) target : target.getClass()); Object possiblyConvertedNewValue = newValue; TypeDescriptor typeDescriptor = getTypeDescriptor(context, target, name); if (typeDescriptor != null) { try { possiblyConvertedNewValue = context .getTypeConverter() .convertValue(newValue, TypeDescriptor.forObject(newValue), typeDescriptor); } catch (EvaluationException evaluationException) { throw new AccessException("Type conversion failure", evaluationException); } } PropertyCacheKey cacheKey = new PropertyCacheKey(type, name, target instanceof Class); Member cachedMember = this.writerCache.get(cacheKey); if (cachedMember == null || cachedMember instanceof Method) { Method method = (Method) cachedMember; if (method == null) { method = findSetterForProperty(name, type, target); if (method != null) { cachedMember = method; this.writerCache.put(cacheKey, cachedMember); } } if (method != null) { try { ReflectionUtils.makeAccessible(method); method.invoke(target, possiblyConvertedNewValue); return; } catch (Exception ex) { throw new AccessException( "Unable to access property '" + name + "' through setter method", ex); } } } if (cachedMember == null || cachedMember instanceof Field) { Field field = (Field) cachedMember; if (field == null) { field = findField(name, type, target); if (field != null) { cachedMember = field; this.writerCache.put(cacheKey, cachedMember); } } if (field != null) { try { ReflectionUtils.makeAccessible(field); field.set(target, possiblyConvertedNewValue); return; } catch (Exception ex) { throw new AccessException("Unable to access field '" + name + "'", ex); } } } throw new AccessException("Neither setter method nor field found for property '" + name + "'"); }