org.springframework.util.ReflectionUtils.MethodFilter#org.springframework.core.MethodIntrospector源码实例Demo

下面列出了org.springframework.util.ReflectionUtils.MethodFilter#org.springframework.core.MethodIntrospector 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。

/**
 * Detect if the given handler has any methods that can handle messages and if
 * so register it with the extracted mapping information.
 * <p><strong>Note:</strong> This method is protected and can be invoked by
 * sub-classes, but this should be done on startup only as documented in
 * {@link #registerHandlerMethod}.
 * @param handler the handler to check, either an instance of a Spring bean name
 */
protected final void detectHandlerMethods(Object handler) {
	Class<?> handlerType;
	if (handler instanceof String) {
		ApplicationContext context = getApplicationContext();
		Assert.state(context != null, "ApplicationContext is required for resolving handler bean names");
		handlerType = context.getType((String) handler);
	}
	else {
		handlerType = handler.getClass();
	}
	if (handlerType != null) {
		final Class<?> userType = ClassUtils.getUserClass(handlerType);
		Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
				(MethodIntrospector.MetadataLookup<T>) method -> getMappingForMethod(method, userType));
		if (logger.isDebugEnabled()) {
			logger.debug(formatMappings(userType, methods));
		}
		methods.forEach((key, value) -> registerHandlerMethod(handler, key, value));
	}
}
 
/**
 * Detect if the given handler has any methods that can handle messages and if
 * so register it with the extracted mapping information.
 * @param handler the handler to check, either an instance of a Spring bean name
 */
protected final void detectHandlerMethods(final Object handler) {
	Class<?> handlerType;
	if (handler instanceof String) {
		ApplicationContext context = getApplicationContext();
		Assert.state(context != null, "ApplicationContext is required for resolving handler bean names");
		handlerType = context.getType((String) handler);
	}
	else {
		handlerType = handler.getClass();
	}

	if (handlerType != null) {
		final Class<?> userType = ClassUtils.getUserClass(handlerType);
		Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
				(MethodIntrospector.MetadataLookup<T>) method -> getMappingForMethod(method, userType));
		if (logger.isDebugEnabled()) {
			logger.debug(formatMappings(userType, methods));
		}
		methods.forEach((key, value) -> registerHandlerMethod(handler, key, value));
	}
}
 
/**
 * Look for handler methods in a handler.
 * @param handler the bean name of a handler or a handler instance
 */
protected void detectHandlerMethods(final Object handler) {
	Class<?> handlerType = (handler instanceof String ?
			obtainApplicationContext().getType((String) handler) : handler.getClass());

	if (handlerType != null) {
		final Class<?> userType = ClassUtils.getUserClass(handlerType);
		Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
				(MethodIntrospector.MetadataLookup<T>) method -> getMappingForMethod(method, userType));
		if (logger.isTraceEnabled()) {
			logger.trace(formatMappings(userType, methods));
		}
		methods.forEach((method, mapping) -> {
			Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
			registerHandlerMethod(handler, invocableMethod, mapping);
		});
	}
}
 
private static Method getMethod(Class<?> controllerType, final String methodName, final Object... args) {
	MethodFilter selector = method -> {
		String name = method.getName();
		int argLength = method.getParameterCount();
		return (name.equals(methodName) && argLength == args.length);
	};
	Set<Method> methods = MethodIntrospector.selectMethods(controllerType, selector);
	if (methods.size() == 1) {
		return methods.iterator().next();
	}
	else if (methods.size() > 1) {
		throw new IllegalArgumentException(String.format(
				"Found two methods named '%s' accepting arguments %s in controller %s: [%s]",
				methodName, Arrays.asList(args), controllerType.getName(), methods));
	}
	else {
		throw new IllegalArgumentException("No method named '" + methodName + "' with " + args.length +
				" arguments found in controller " + controllerType.getName());
	}
}
 
/**
 * Detect if the given handler has any methods that can handle messages and if
 * so register it with the extracted mapping information.
 * @param handler the handler to check, either an instance of a Spring bean name
 */
protected final void detectHandlerMethods(final Object handler) {
	Class<?> handlerType;
	if (handler instanceof String) {
		ApplicationContext context = getApplicationContext();
		Assert.state(context != null, "ApplicationContext is required for resolving handler bean names");
		handlerType = context.getType((String) handler);
	}
	else {
		handlerType = handler.getClass();
	}

	if (handlerType != null) {
		final Class<?> userType = ClassUtils.getUserClass(handlerType);
		Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
				(MethodIntrospector.MetadataLookup<T>) method -> getMappingForMethod(method, userType));
		if (logger.isDebugEnabled()) {
			logger.debug(methods.size() + " message handler methods found on " + userType + ": " + methods);
		}
		methods.forEach((key, value) -> registerHandlerMethod(handler, key, value));
	}
}
 
/**
 * Look for handler methods in a handler.
 * @param handler the bean name of a handler or a handler instance
 */
protected void detectHandlerMethods(final Object handler) {
	Class<?> handlerType = (handler instanceof String ?
			obtainApplicationContext().getType((String) handler) : handler.getClass());

	if (handlerType != null) {
		final Class<?> userType = ClassUtils.getUserClass(handlerType);
		Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
				(MethodIntrospector.MetadataLookup<T>) method -> getMappingForMethod(method, userType));
		if (logger.isTraceEnabled()) {
			logger.trace(formatMappings(userType, methods));
		}
		methods.forEach((key, mapping) -> {
			Method invocableMethod = AopUtils.selectInvocableMethod(key, userType);
			registerHandlerMethod(handler, invocableMethod, mapping);
		});
	}
}
 
private static Method getMethod(Class<?> controllerType, final String methodName, final Object... args) {
	MethodFilter selector = method -> {
		String name = method.getName();
		int argLength = method.getParameterCount();
		return (name.equals(methodName) && argLength == args.length);
	};
	Set<Method> methods = MethodIntrospector.selectMethods(controllerType, selector);
	if (methods.size() == 1) {
		return methods.iterator().next();
	}
	else if (methods.size() > 1) {
		throw new IllegalArgumentException(String.format(
				"Found two methods named '%s' accepting arguments %s in controller %s: [%s]",
				methodName, Arrays.asList(args), controllerType.getName(), methods));
	}
	else {
		throw new IllegalArgumentException("No method named '" + methodName + "' with " + args.length +
				" arguments found in controller " + controllerType.getName());
	}
}
 
/**
 * Look for handler methods in the specified handler bean.
 * @param handler either a bean name or an actual handler instance
 * @see #getMappingForMethod
 */
protected void detectHandlerMethods(Object handler) {
	Class<?> handlerType = (handler instanceof String ?
			obtainApplicationContext().getType((String) handler) : handler.getClass());

	if (handlerType != null) {
		Class<?> userType = ClassUtils.getUserClass(handlerType);
		Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
				(MethodIntrospector.MetadataLookup<T>) method -> {
					try {
						return getMappingForMethod(method, userType);
					}
					catch (Throwable ex) {
						throw new IllegalStateException("Invalid mapping on handler class [" +
								userType.getName() + "]: " + method, ex);
					}
				});
		if (logger.isTraceEnabled()) {
			logger.trace(formatMappings(userType, methods));
		}
		methods.forEach((method, mapping) -> {
			Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
			registerHandlerMethod(handler, invocableMethod, mapping);
		});
	}
}
 
源代码9 项目: faster-framework-project   文件: ClientFactory.java
public Object createClientProxy(Class<?> target) {
    GRpcService grpcService = target.getAnnotation(GRpcService.class);
    ChannelProperty channelProperty = serverChannelMap.get(grpcService.value());
    if (channelProperty == null) {
        throw new GRpcChannelCreateException("GRpcService scheme:{" + grpcService.value() + "} was not found in properties.Please check your configuration.");
    }
    ManageChannelProxy manageChannelProxy = new ManageChannelProxy(channelProperty, marshallerFactory);
    //获取该类下所有包含GrpcMethod的注解,创建call定义
    Map<Method, GRpcMethod> annotatedMethods = MethodIntrospector.selectMethods(target,
            (MethodIntrospector.MetadataLookup<GRpcMethod>) method -> AnnotatedElementUtils.findMergedAnnotation(method, GRpcMethod.class));
    annotatedMethods.forEach((k, v) -> {
        String annotationMethodName = v.value();
        MethodCallProperty methodCallProperty = new MethodCallProperty();
        methodCallProperty.setMethod(k);
        methodCallProperty.setMethodName(StringUtils.isEmpty(annotationMethodName) ? k.getName() : annotationMethodName);
        methodCallProperty.setMethodType(v.type());
        methodCallProperty.setScheme(grpcService.scheme());
        manageChannelProxy.addCall(methodCallProperty);
    });
    return Proxy.newProxyInstance(target.getClassLoader(), new Class[]{target}, manageChannelProxy);
}
 
源代码10 项目: lams   文件: MvcUriComponentsBuilder.java
private static Method getMethod(Class<?> controllerType, final String methodName, final Object... args) {
	MethodFilter selector = new MethodFilter() {
		@Override
		public boolean matches(Method method) {
			String name = method.getName();
			int argLength = method.getParameterTypes().length;
			return (name.equals(methodName) && argLength == args.length);
		}
	};
	Set<Method> methods = MethodIntrospector.selectMethods(controllerType, selector);
	if (methods.size() == 1) {
		return methods.iterator().next();
	}
	else if (methods.size() > 1) {
		throw new IllegalArgumentException(String.format(
				"Found two methods named '%s' accepting arguments %s in controller %s: [%s]",
				methodName, Arrays.asList(args), controllerType.getName(), methods));
	}
	else {
		throw new IllegalArgumentException("No method named '" + methodName + "' with " + args.length +
				" arguments found in controller " + controllerType.getName());
	}
}
 
/**
 * Detect if the given handler has any methods that can handle messages and if
 * so register it with the extracted mapping information.
 * @param handler the handler to check, either an instance of a Spring bean name
 */
protected final void detectHandlerMethods(final Object handler) {
	Class<?> handlerType = (handler instanceof String ?
			this.applicationContext.getType((String) handler) : handler.getClass());
	final Class<?> userType = ClassUtils.getUserClass(handlerType);

	Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
			new MethodIntrospector.MetadataLookup<T>() {
				@Override
				public T inspect(Method method) {
					return getMappingForMethod(method, userType);
				}
			});

	if (logger.isDebugEnabled()) {
		logger.debug(methods.size() + " message handler methods found on " + userType + ": " + methods);
	}
	for (Map.Entry<Method, T> entry : methods.entrySet()) {
		registerHandlerMethod(handler, entry.getKey(), entry.getValue());
	}
}
 
private static Method getMethod(Class<?> controllerType, final String methodName, final Object... args) {
	MethodFilter selector = new MethodFilter() {
		@Override
		public boolean matches(Method method) {
			String name = method.getName();
			int argLength = method.getParameterTypes().length;
			return (name.equals(methodName) && argLength == args.length);
		}
	};
	Set<Method> methods = MethodIntrospector.selectMethods(controllerType, selector);
	if (methods.size() == 1) {
		return methods.iterator().next();
	}
	else if (methods.size() > 1) {
		throw new IllegalArgumentException(String.format(
				"Found two methods named '%s' accepting arguments %s in controller %s: [%s]",
				methodName, Arrays.asList(args), controllerType.getName(), methods));
	}
	else {
		throw new IllegalArgumentException("No method named '" + methodName + "' with " + args.length +
				" arguments found in controller " + controllerType.getName());
	}
}
 
/**
 * Look for handler methods in a handler.
 * @param handler the bean name of a handler or a handler instance
 */
protected void detectHandlerMethods(final Object handler) {
	Class<?> handlerType = (handler instanceof String ?
			getApplicationContext().getType((String) handler) : handler.getClass());
	final Class<?> userType = ClassUtils.getUserClass(handlerType);

	Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
			new MethodIntrospector.MetadataLookup<T>() {
				@Override
				public T inspect(Method method) {
					return getMappingForMethod(method, userType);
				}
			});

	if (logger.isDebugEnabled()) {
		logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
	}
	for (Map.Entry<Method, T> entry : methods.entrySet()) {
		registerHandlerMethod(handler, entry.getKey(), entry.getValue());
	}
}
 
private static Map<Class<? extends Throwable>, Method> initExceptionMappings(Class<?> handlerType) {
	Map<Class<? extends Throwable>, Method> result = new HashMap<>();
	for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHOD_FILTER)) {
		for (Class<? extends Throwable> exception : getExceptionsFromMethodSignature(method)) {
			result.put(exception, method);
		}
	}
	return result;
}
 
源代码15 项目: spring-analysis-note   文件: AopUtils.java
/**
 * Select an invocable method on the target type: either the given method itself
 * if actually exposed on the target type, or otherwise a corresponding method
 * on one of the target type's interfaces or on the target type itself.
 * @param method the method to check
 * @param targetType the target type to search methods on (typically an AOP proxy)
 * @return a corresponding invocable method on the target type
 * @throws IllegalStateException if the given method is not invocable on the given
 * target type (typically due to a proxy mismatch)
 * @since 4.3
 * @see MethodIntrospector#selectInvocableMethod(Method, Class)
 */
public static Method selectInvocableMethod(Method method, @Nullable Class<?> targetType) {
	if (targetType == null) {
		return method;
	}
	Method methodToUse = MethodIntrospector.selectInvocableMethod(method, targetType);
	if (Modifier.isPrivate(methodToUse.getModifiers()) && !Modifier.isStatic(methodToUse.getModifiers()) &&
			SpringProxy.class.isAssignableFrom(targetType)) {
		throw new IllegalStateException(String.format(
				"Need to invoke method '%s' found on proxy for target class '%s' but cannot " +
				"be delegated to target bean. Switch its visibility to package or protected.",
				method.getName(), method.getDeclaringClass().getSimpleName()));
	}
	return methodToUse;
}
 
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
	if (bean instanceof AopInfrastructureBean || bean instanceof TaskScheduler ||
			bean instanceof ScheduledExecutorService) {
		// Ignore AOP infrastructure such as scoped proxies.
		return bean;
	}

	Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);
	if (!this.nonAnnotatedClasses.contains(targetClass) &&
			AnnotationUtils.isCandidateClass(targetClass, Arrays.asList(Scheduled.class, Schedules.class))) {
		Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
				(MethodIntrospector.MetadataLookup<Set<Scheduled>>) method -> {
					Set<Scheduled> scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(
							method, Scheduled.class, Schedules.class);
					return (!scheduledMethods.isEmpty() ? scheduledMethods : null);
				});
		if (annotatedMethods.isEmpty()) {
			this.nonAnnotatedClasses.add(targetClass);
			if (logger.isTraceEnabled()) {
				logger.trace("No @Scheduled annotations found on bean class: " + targetClass);
			}
		}
		else {
			// Non-empty set of methods
			annotatedMethods.forEach((method, scheduledMethods) ->
					scheduledMethods.forEach(scheduled -> processScheduled(scheduled, method, bean)));
			if (logger.isTraceEnabled()) {
				logger.trace(annotatedMethods.size() + " @Scheduled methods processed on bean '" + beanName +
						"': " + annotatedMethods);
			}
		}
	}
	return bean;
}
 
private void initControllerAdviceCaches(ApplicationContext applicationContext) {
	List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(applicationContext);
	AnnotationAwareOrderComparator.sort(beans);

	for (ControllerAdviceBean bean : beans) {
		Class<?> beanType = bean.getBeanType();
		if (beanType != null) {
			Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
			if (!attrMethods.isEmpty()) {
				this.modelAttributeAdviceCache.put(bean, attrMethods);
			}
			Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
			if (!binderMethods.isEmpty()) {
				this.initBinderAdviceCache.put(bean, binderMethods);
			}
			ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType);
			if (resolver.hasExceptionMappings()) {
				this.exceptionHandlerAdviceCache.put(bean, resolver);
			}
		}
	}

	if (logger.isDebugEnabled()) {
		int modelSize = this.modelAttributeAdviceCache.size();
		int binderSize = this.initBinderAdviceCache.size();
		int handlerSize = this.exceptionHandlerAdviceCache.size();
		if (modelSize == 0 && binderSize == 0 && handlerSize == 0) {
			logger.debug("ControllerAdvice beans: none");
		}
		else {
			logger.debug("ControllerAdvice beans: " + modelSize + " @ModelAttribute, " + binderSize +
					" @InitBinder, " + handlerSize + " @ExceptionHandler");
		}
	}
}
 
private InitBinderBindingContext getBindingContext(Object controller) {
	List<SyncInvocableHandlerMethod> binderMethods =
			MethodIntrospector.selectMethods(controller.getClass(), BINDER_METHODS)
					.stream()
					.map(method -> new SyncInvocableHandlerMethod(controller, method))
					.collect(Collectors.toList());

	WebBindingInitializer bindingInitializer = new ConfigurableWebBindingInitializer();
	return new InitBinderBindingContext(bindingInitializer, binderMethods);
}
 
/**
 * Look for handler methods in the specified handler bean.
 *
 * 在指定的处理程序bean中查找处理程序方法。
 *
 * @param handler either a bean name or an actual handler instance
 * @see #getMappingForMethod
 */
protected void detectHandlerMethods(Object handler) {
	Class<?> handlerType = (handler instanceof String ?
			obtainApplicationContext().getType((String) handler) : handler.getClass());

	if (handlerType != null) {
		Class<?> userType = ClassUtils.getUserClass(handlerType);
		// 通过反射,获取类中所有方法
		// 筛选出 public 类型,并且带有 @RequestMapping 注解的方法
		Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
				(MethodIntrospector.MetadataLookup<T>) method -> {
					try {
						// 通过 RequestMappingHandlerMapping.getMappingForMethod 方法组装成 RequestMappingInfo(映射关系)
						return getMappingForMethod(method, userType);
					}
					catch (Throwable ex) {
						throw new IllegalStateException("Invalid mapping on handler class [" +
								userType.getName() + "]: " + method, ex);
					}
				});
		if (logger.isTraceEnabled()) {
			logger.trace(formatMappings(userType, methods));
		}
		methods.forEach((method, mapping) -> {
			Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
			// 通过 mappingRegistry 进行注册上面获取到的映射关系
			registerHandlerMethod(handler, invocableMethod, mapping);
		});
	}
}
 
/**
 * A constructor that finds {@link ExceptionHandler} methods in the given type.
 * @param handlerType the type to introspect
 */
public ExceptionHandlerMethodResolver(Class<?> handlerType) {
	for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS)) {
		for (Class<? extends Throwable> exceptionType : detectExceptionMappings(method)) {
			addExceptionMapping(exceptionType, method);
		}
	}
}
 
private void runTest(Object controller) throws Exception {
	HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
	resolvers.addResolver(new ModelAttributeMethodProcessor(false));
	resolvers.addResolver(new ModelMethodProcessor());
	WebDataBinderFactory dataBinderFactory = new DefaultDataBinderFactory(null);

	Class<?> type = controller.getClass();
	Set<Method> methods = MethodIntrospector.selectMethods(type, METHOD_FILTER);
	List<InvocableHandlerMethod> modelMethods = new ArrayList<>();
	for (Method method : methods) {
		InvocableHandlerMethod modelMethod = new InvocableHandlerMethod(controller, method);
		modelMethod.setHandlerMethodArgumentResolvers(resolvers);
		modelMethod.setDataBinderFactory(dataBinderFactory);
		modelMethods.add(modelMethod);
	}
	Collections.shuffle(modelMethods);

	SessionAttributesHandler sessionHandler = new SessionAttributesHandler(type, this.sessionAttributeStore);
	ModelFactory factory = new ModelFactory(modelMethods, dataBinderFactory, sessionHandler);
	factory.initModel(this.webRequest, this.mavContainer, new HandlerMethod(controller, "handle"));
	if (logger.isDebugEnabled()) {
		StringBuilder sb = new StringBuilder();
		for (String name : getInvokedMethods()) {
			sb.append(" >> ").append(name);
		}
		logger.debug(sb);
	}
}
 
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
	if (bean instanceof AopInfrastructureBean || bean instanceof JmsListenerContainerFactory ||
			bean instanceof JmsListenerEndpointRegistry) {
		// Ignore AOP infrastructure such as scoped proxies.
		return bean;
	}

	Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);
	if (!this.nonAnnotatedClasses.contains(targetClass) &&
			AnnotationUtils.isCandidateClass(targetClass, JmsListener.class)) {
		Map<Method, Set<JmsListener>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
				(MethodIntrospector.MetadataLookup<Set<JmsListener>>) method -> {
					Set<JmsListener> listenerMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(
							method, JmsListener.class, JmsListeners.class);
					return (!listenerMethods.isEmpty() ? listenerMethods : null);
				});
		if (annotatedMethods.isEmpty()) {
			this.nonAnnotatedClasses.add(targetClass);
			if (logger.isTraceEnabled()) {
				logger.trace("No @JmsListener annotations found on bean type: " + targetClass);
			}
		}
		else {
			// Non-empty set of methods
			annotatedMethods.forEach((method, listeners) ->
					listeners.forEach(listener -> processJmsListener(listener, method, bean)));
			if (logger.isDebugEnabled()) {
				logger.debug(annotatedMethods.size() + " @JmsListener methods processed on bean '" + beanName +
						"': " + annotatedMethods);
			}
		}
	}
	return bean;
}
 
private static Map<Class<? extends Throwable>, Method> initExceptionMappings(Class<?> handlerType) {
	Map<Class<? extends Throwable>, Method> result = new HashMap<>();
	for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHOD_FILTER)) {
		for (Class<? extends Throwable> exception : getExceptionsFromMethodSignature(method)) {
			result.put(exception, method);
		}
	}
	return result;
}
 
源代码24 项目: java-technology-stack   文件: AopUtils.java
/**
 * Select an invocable method on the target type: either the given method itself
 * if actually exposed on the target type, or otherwise a corresponding method
 * on one of the target type's interfaces or on the target type itself.
 * @param method the method to check
 * @param targetType the target type to search methods on (typically an AOP proxy)
 * @return a corresponding invocable method on the target type
 * @throws IllegalStateException if the given method is not invocable on the given
 * target type (typically due to a proxy mismatch)
 * @since 4.3
 * @see MethodIntrospector#selectInvocableMethod(Method, Class)
 */
public static Method selectInvocableMethod(Method method, @Nullable Class<?> targetType) {
	if (targetType == null) {
		return method;
	}
	Method methodToUse = MethodIntrospector.selectInvocableMethod(method, targetType);
	if (Modifier.isPrivate(methodToUse.getModifiers()) && !Modifier.isStatic(methodToUse.getModifiers()) &&
			SpringProxy.class.isAssignableFrom(targetType)) {
		throw new IllegalStateException(String.format(
				"Need to invoke method '%s' found on proxy for target class '%s' but cannot " +
				"be delegated to target bean. Switch its visibility to package or protected.",
				method.getName(), method.getDeclaringClass().getSimpleName()));
	}
	return methodToUse;
}
 
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
	if (bean instanceof AopInfrastructureBean || bean instanceof TaskScheduler ||
			bean instanceof ScheduledExecutorService) {
		// Ignore AOP infrastructure such as scoped proxies.
		return bean;
	}

	Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);
	if (!this.nonAnnotatedClasses.contains(targetClass)) {
		Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
				(MethodIntrospector.MetadataLookup<Set<Scheduled>>) method -> {
					Set<Scheduled> scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(
							method, Scheduled.class, Schedules.class);
					return (!scheduledMethods.isEmpty() ? scheduledMethods : null);
				});
		if (annotatedMethods.isEmpty()) {
			this.nonAnnotatedClasses.add(targetClass);
			if (logger.isTraceEnabled()) {
				logger.trace("No @Scheduled annotations found on bean class: " + targetClass);
			}
		}
		else {
			// Non-empty set of methods
			annotatedMethods.forEach((method, scheduledMethods) ->
					scheduledMethods.forEach(scheduled -> processScheduled(scheduled, method, bean)));
			if (logger.isTraceEnabled()) {
				logger.trace(annotatedMethods.size() + " @Scheduled methods processed on bean '" + beanName +
						"': " + annotatedMethods);
			}
		}
	}
	return bean;
}
 
private void initControllerAdviceCaches(ApplicationContext applicationContext) {
	List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(applicationContext);
	AnnotationAwareOrderComparator.sort(beans);

	for (ControllerAdviceBean bean : beans) {
		Class<?> beanType = bean.getBeanType();
		if (beanType != null) {
			Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
			if (!attrMethods.isEmpty()) {
				this.modelAttributeAdviceCache.put(bean, attrMethods);
			}
			Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
			if (!binderMethods.isEmpty()) {
				this.initBinderAdviceCache.put(bean, binderMethods);
			}
			ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType);
			if (resolver.hasExceptionMappings()) {
				this.exceptionHandlerAdviceCache.put(bean, resolver);
			}
		}
	}

	if (logger.isDebugEnabled()) {
		int modelSize = this.modelAttributeAdviceCache.size();
		int binderSize = this.initBinderAdviceCache.size();
		int handlerSize = this.exceptionHandlerAdviceCache.size();
		if (modelSize == 0 && binderSize == 0 && handlerSize == 0) {
			logger.debug("ControllerAdvice beans: none");
		}
		else {
			logger.debug("ControllerAdvice beans: " + modelSize + " @ModelAttribute, " + binderSize +
					" @InitBinder, " + handlerSize + " @ExceptionHandler");
		}
	}
}
 
private InitBinderBindingContext getBindingContext(Object controller) {

		List<SyncInvocableHandlerMethod> binderMethods =
				MethodIntrospector.selectMethods(controller.getClass(), BINDER_METHODS)
						.stream()
						.map(method -> new SyncInvocableHandlerMethod(controller, method))
						.collect(Collectors.toList());

		WebBindingInitializer bindingInitializer = new ConfigurableWebBindingInitializer();
		return new InitBinderBindingContext(bindingInitializer, binderMethods);
	}
 
/**
 * A constructor that finds {@link ExceptionHandler} methods in the given type.
 * @param handlerType the type to introspect
 */
public ExceptionHandlerMethodResolver(Class<?> handlerType) {
	for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS)) {
		for (Class<? extends Throwable> exceptionType : detectExceptionMappings(method)) {
			addExceptionMapping(exceptionType, method);
		}
	}
}
 
private void runTest(Object controller) throws Exception {
	HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
	resolvers.addResolver(new ModelAttributeMethodProcessor(false));
	resolvers.addResolver(new ModelMethodProcessor());
	WebDataBinderFactory dataBinderFactory = new DefaultDataBinderFactory(null);

	Class<?> type = controller.getClass();
	Set<Method> methods = MethodIntrospector.selectMethods(type, METHOD_FILTER);
	List<InvocableHandlerMethod> modelMethods = new ArrayList<>();
	for (Method method : methods) {
		InvocableHandlerMethod modelMethod = new InvocableHandlerMethod(controller, method);
		modelMethod.setHandlerMethodArgumentResolvers(resolvers);
		modelMethod.setDataBinderFactory(dataBinderFactory);
		modelMethods.add(modelMethod);
	}
	Collections.shuffle(modelMethods);

	SessionAttributesHandler sessionHandler = new SessionAttributesHandler(type, this.sessionAttributeStore);
	ModelFactory factory = new ModelFactory(modelMethods, dataBinderFactory, sessionHandler);
	factory.initModel(this.webRequest, this.mavContainer, new HandlerMethod(controller, "handle"));
	if (logger.isDebugEnabled()) {
		StringBuilder sb = new StringBuilder();
		for (String name : getInvokedMethods()) {
			sb.append(" >> ").append(name);
		}
		logger.debug(sb);
	}
}
 
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
	if (bean instanceof AopInfrastructureBean || bean instanceof JmsListenerContainerFactory ||
			bean instanceof JmsListenerEndpointRegistry) {
		// Ignore AOP infrastructure such as scoped proxies.
		return bean;
	}

	Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);
	if (!this.nonAnnotatedClasses.contains(targetClass)) {
		Map<Method, Set<JmsListener>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
				(MethodIntrospector.MetadataLookup<Set<JmsListener>>) method -> {
					Set<JmsListener> listenerMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(
							method, JmsListener.class, JmsListeners.class);
					return (!listenerMethods.isEmpty() ? listenerMethods : null);
				});
		if (annotatedMethods.isEmpty()) {
			this.nonAnnotatedClasses.add(targetClass);
			if (logger.isTraceEnabled()) {
				logger.trace("No @JmsListener annotations found on bean type: " + targetClass);
			}
		}
		else {
			// Non-empty set of methods
			annotatedMethods.forEach((method, listeners) ->
					listeners.forEach(listener -> processJmsListener(listener, method, bean)));
			if (logger.isDebugEnabled()) {
				logger.debug(annotatedMethods.size() + " @JmsListener methods processed on bean '" + beanName +
						"': " + annotatedMethods);
			}
		}
	}
	return bean;
}