/** * If the provided instance contains a bean name rather than an object instance, * the bean name is resolved before a {@link HandlerMethod} is created and returned. */ public HandlerMethod createWithResolvedBean() { Object handler = this.bean; if (this.bean instanceof String) { Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory"); String beanName = (String) this.bean; handler = this.beanFactory.getBean(beanName); } return new HandlerMethod(this, handler); }
Match secondBestMatch = matches.get(1); if (comparator.compare(bestMatch, secondBestMatch) == 0) { Method m1 = bestMatch.handlerMethod.getMethod(); Method m2 = secondBestMatch.handlerMethod.getMethod(); throw new IllegalStateException("Ambiguous handler methods mapped for destination '" + lookupDestination + "': {" + m1 + ", " + m2 + "}");
protected void handleMatch(T mapping, HandlerMethod handlerMethod, String lookupDestination, Message<?> message) { if (logger.isDebugEnabled()) { logger.debug("Invoking " + handlerMethod.getShortLogMessage()); handlerMethod = handlerMethod.createWithResolvedBean(); InvocableHandlerMethod invocable = new InvocableHandlerMethod(handlerMethod); if (this.handlerMethodLogger != null) { try { Object returnValue = invocable.invoke(message); MethodParameter returnType = handlerMethod.getReturnType(); if (void.class == returnType.getParameterType()) { return;
protected String formatInvokeError(String text, Object[] args) { String formattedArgs = IntStream.range(0, args.length) .mapToObj(i -> (args[i] != null ? "[" + i + "] [type=" + args[i].getClass().getName() + "] [value=" + args[i] + "]" : "[" + i + "] [null]")) .collect(Collectors.joining(",\n", " ", " ")); return text + "\n" + "Endpoint [" + getBeanType().getName() + "]\n" + "Method [" + getBridgedMethod().toGenericString() + "] " + "with argument values:\n" + formattedArgs; }
/** * Register a handler method and its unique mapping. * @param handler the bean name of the handler or the handler instance * @param method the method to register * @param mapping the mapping conditions associated with the handler method * @throws IllegalStateException if another method was already registered * under the same mapping */ protected void registerHandlerMethod(Object handler, Method method, T mapping) { Assert.notNull(mapping, "Mapping must not be null"); HandlerMethod newHandlerMethod = createHandlerMethod(handler, method); HandlerMethod oldHandlerMethod = this.handlerMethods.get(mapping); if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) { throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + newHandlerMethod.getBean() + "' bean method \n" + newHandlerMethod + "\nto " + mapping + ": There is already '" + oldHandlerMethod.getBean() + "' bean method\n" + oldHandlerMethod + " mapped."); } this.handlerMethods.put(mapping, newHandlerMethod); if (logger.isTraceEnabled()) { logger.trace("Mapped \"" + mapping + "\" onto " + newHandlerMethod); } for (String pattern : getDirectLookupDestinations(mapping)) { this.destinationLookup.add(pattern, mapping); } }
logger.debug("Searching methods to handle " + exception.getClass().getSimpleName()); Class<?> beanType = handlerMethod.getBeanType(); AbstractExceptionHandlerMethodResolver resolver = this.exceptionHandlerCache.get(beanType); if (resolver == null) { return new InvocableHandlerMethod(handlerMethod.getBean(), method);
@Override public Class<?> getContainingClass() { return HandlerMethod.this.getBeanType(); }
/** * Return {@code true} if the method return type is void, {@code false} otherwise. */ public boolean isVoid() { return Void.TYPE.equals(getReturnType().getParameterType()); }
@Override public <T extends Annotation> T getMethodAnnotation(Class<T> annotationType) { return HandlerMethod.this.getMethodAnnotation(annotationType); }
/** * Assert that the target bean class is an instance of the class where the given * method is declared. In some cases the actual endpoint instance at request- * processing time may be a JDK dynamic proxy (lazy initialization, prototype * beans, and others). Endpoint classes that require proxying should prefer * class-based proxy mechanisms. */ protected void assertTargetBean(Method method, Object targetBean, Object[] args) { Class<?> methodDeclaringClass = method.getDeclaringClass(); Class<?> targetBeanClass = targetBean.getClass(); if (!methodDeclaringClass.isAssignableFrom(targetBeanClass)) { String text = "The mapped handler method class '" + methodDeclaringClass.getName() + "' is not an instance of the actual endpoint bean class '" + targetBeanClass.getName() + "'. If the endpoint requires proxying " + "(e.g. due to @Transactional), please use class-based proxying."; throw new IllegalStateException(formatInvokeError(text, args)); } }
protected String formatInvokeError(String text, Object[] args) { String formattedArgs = IntStream.range(0, args.length) .mapToObj(i -> (args[i] != null ? "[" + i + "] [type=" + args[i].getClass().getName() + "] [value=" + args[i] + "]" : "[" + i + "] [null]")) .collect(Collectors.joining(",\n", " ", " ")); return text + "\n" + "Endpoint [" + getBeanType().getName() + "]\n" + "Method [" + getBridgedMethod().toGenericString() + "] " + "with argument values:\n" + formattedArgs; }
/** * Register a handler method and its unique mapping. * @param handler the bean name of the handler or the handler instance * @param method the method to register * @param mapping the mapping conditions associated with the handler method * @throws IllegalStateException if another method was already registered * under the same mapping */ protected void registerHandlerMethod(Object handler, Method method, T mapping) { Assert.notNull(mapping, "Mapping must not be null"); HandlerMethod newHandlerMethod = createHandlerMethod(handler, method); HandlerMethod oldHandlerMethod = this.handlerMethods.get(mapping); if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) { throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + newHandlerMethod.getBean() + "' bean method \n" + newHandlerMethod + "\nto " + mapping + ": There is already '" + oldHandlerMethod.getBean() + "' bean method\n" + oldHandlerMethod + " mapped."); } this.handlerMethods.put(mapping, newHandlerMethod); if (logger.isTraceEnabled()) { logger.trace("Mapped \"" + mapping + "\" onto " + newHandlerMethod); } for (String pattern : getDirectLookupDestinations(mapping)) { this.destinationLookup.add(pattern, mapping); } }
logger.debug("Searching methods to handle " + exception.getClass().getSimpleName()); Class<?> beanType = handlerMethod.getBeanType(); AbstractExceptionHandlerMethodResolver resolver = this.exceptionHandlerCache.get(beanType); if (resolver == null) { return new InvocableHandlerMethod(handlerMethod.getBean(), method);
/** * Return a short representation of this handler method for log message purposes. */ public String getShortLogMessage() { int args = this.method.getParameterCount(); return getBeanType().getName() + "#" + this.method.getName() + "[" + args + " args]"; }
/** * Return {@code true} if the method return type is void, {@code false} otherwise. */ public boolean isVoid() { return Void.TYPE.equals(getReturnType().getParameterType()); }
@Override public <T extends Annotation> T getMethodAnnotation(Class<T> annotationType) { return HandlerMethod.this.getMethodAnnotation(annotationType); }
/** * Assert that the target bean class is an instance of the class where the given * method is declared. In some cases the actual endpoint instance at request- * processing time may be a JDK dynamic proxy (lazy initialization, prototype * beans, and others). Endpoint classes that require proxying should prefer * class-based proxy mechanisms. */ protected void assertTargetBean(Method method, Object targetBean, Object[] args) { Class<?> methodDeclaringClass = method.getDeclaringClass(); Class<?> targetBeanClass = targetBean.getClass(); if (!methodDeclaringClass.isAssignableFrom(targetBeanClass)) { String text = "The mapped handler method class '" + methodDeclaringClass.getName() + "' is not an instance of the actual endpoint bean class '" + targetBeanClass.getName() + "'. If the endpoint requires proxying " + "(e.g. due to @Transactional), please use class-based proxying."; throw new IllegalStateException(formatInvokeError(text, args)); } }
protected void handleMatch(T mapping, HandlerMethod handlerMethod, String lookupDestination, Message<?> message) { if (logger.isDebugEnabled()) { logger.debug("Invoking " + handlerMethod.getShortLogMessage()); handlerMethod = handlerMethod.createWithResolvedBean(); InvocableHandlerMethod invocable = new InvocableHandlerMethod(handlerMethod); if (this.handlerMethodLogger != null) { try { Object returnValue = invocable.invoke(message); MethodParameter returnType = handlerMethod.getReturnType(); if (void.class == returnType.getParameterType()) { return;
/** * Create a HandlerMethod instance from an Object handler that is either a handler * instance or a String-based bean name. */ protected HandlerMethod createHandlerMethod(Object handler, Method method) { HandlerMethod handlerMethod; if (handler instanceof String) { ApplicationContext context = getApplicationContext(); Assert.state(context != null, "ApplicationContext is required for resolving handler bean names"); String beanName = (String) handler; handlerMethod = new HandlerMethod(beanName, context.getAutowireCapableBeanFactory(), method); } else { handlerMethod = new HandlerMethod(handler, method); } return handlerMethod; }
protected String formatInvokeError(String text, Object[] args) { String formattedArgs = IntStream.range(0, args.length) .mapToObj(i -> (args[i] != null ? "[" + i + "] [type=" + args[i].getClass().getName() + "] [value=" + args[i] + "]" : "[" + i + "] [null]")) .collect(Collectors.joining(",\n", " ", " ")); return text + "\n" + "Endpoint [" + getBeanType().getName() + "]\n" + "Method [" + getBridgedMethod().toGenericString() + "] " + "with argument values:\n" + formattedArgs; }