Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,20 @@ public class HandlerMethod {
* Create an instance from a bean instance and a method.
*/
public HandlerMethod(Object bean, Method method) {
this(bean, method, null);
}


/**
* Variant of {@link #HandlerMethod(Object, Method)} that
* also accepts a {@link MessageSource}.
*/
public HandlerMethod(Object bean, Method method, @Nullable MessageSource messageSource) {
Assert.notNull(bean, "Bean is required");
Assert.notNull(method, "Method is required");
this.bean = bean;
this.beanFactory = null;
this.messageSource = null;
this.messageSource = messageSource;
this.beanType = ClassUtils.getUserClass(bean);
this.method = method;
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.lang.reflect.Method;
import java.util.Arrays;

import org.springframework.context.MessageSource;
import org.springframework.core.CoroutinesUtils;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.KotlinDetector;
Expand Down Expand Up @@ -71,6 +72,14 @@ public InvocableHandlerMethod(Object bean, Method method) {
super(bean, method);
}

/**
* Variant of {@link #InvocableHandlerMethod(Object, Method)} that
* also accepts a {@link MessageSource}.
*/
public InvocableHandlerMethod(Object bean, Method method, @Nullable MessageSource messageSource) {
super(bean, method, messageSource);
}

/**
* Construct a new handler method with the given bean instance, method name and parameters.
* @param bean the object bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ protected ServletInvocableHandlerMethod getExceptionHandlerMethod(
}
Method method = resolver.resolveMethod(exception);
if (method != null) {
return new ServletInvocableHandlerMethod(handlerMethod.getBean(), method);
return new ServletInvocableHandlerMethod(handlerMethod.getBean(), method, this.applicationContext);
}
// For advice applicability check below (involving base packages, assignable types
// and annotation presence), use target class instead of interface-based proxy.
Expand All @@ -498,7 +498,7 @@ protected ServletInvocableHandlerMethod getExceptionHandlerMethod(
ExceptionHandlerMethodResolver resolver = entry.getValue();
Method method = resolver.resolveMethod(exception);
if (method != null) {
return new ServletInvocableHandlerMethod(advice.resolveBean(), method);
return new ServletInvocableHandlerMethod(advice.resolveBean(), method, this.applicationContext);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.MessageSource;
import org.springframework.core.KotlinDetector;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
Expand Down Expand Up @@ -68,6 +69,13 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
@Nullable
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;

/**
* Variant of {@link #ServletInvocableHandlerMethod(Object, Method)} that
* also accepts a {@link MessageSource}.
*/
public ServletInvocableHandlerMethod(Object handler, Method method, @Nullable MessageSource messageSource) {
super(handler, method, messageSource);
}

/**
* Creates an instance from the given handler and method.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.SocketTimeoutException;
import java.util.Collections;
import java.util.Locale;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
Expand All @@ -30,8 +32,11 @@
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
Expand All @@ -42,6 +47,7 @@
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.support.WebApplicationObjectSupport;
import org.springframework.web.method.HandlerMethod;
Expand Down Expand Up @@ -333,6 +339,28 @@ void resolveExceptionWithAssertionErrorAsRootCause() throws Exception {
assertThat(this.response.getContentAsString()).isEqualTo(rootCause.toString());
}

@Test //gh-27156
void resolveExceptionWithReasonResovledByMessageSource() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyConfig.class);
StaticApplicationContext context = new StaticApplicationContext(ctx);
Locale locale = Locale.ENGLISH;
context.addMessage("gateway.timeout", locale, "Gateway Timeout");
context.refresh();
LocaleContextHolder.setLocale(locale);
this.resolver.setApplicationContext(context);
this.resolver.afterPropertiesSet();

SocketTimeoutException ex = new SocketTimeoutException();
HandlerMethod handlerMethod = new HandlerMethod(new ResponseBodyController(), "handle");
ModelAndView mav = this.resolver.resolveException(this.request, this.response, handlerMethod, ex);

assertThat(mav).as("Exception was not handled").isNotNull();
assertThat(mav.isEmpty()).isTrue();
assertThat(this.response.getStatus()).isEqualTo(HttpStatus.GATEWAY_TIMEOUT.value());
assertThat(this.response.getErrorMessage()).isEqualTo("Gateway Timeout");
assertThat(this.response.getContentAsString()).isEqualTo("");
}

@Test
void resolveExceptionControllerAdviceHandler() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyControllerAdviceConfig.class);
Expand Down Expand Up @@ -530,6 +558,16 @@ public String handleException(Exception ex) {
}
}

@RestControllerAdvice
@Order(3)
static class ResponseStatusTestExceptionResolver {

@ExceptionHandler(SocketTimeoutException.class)
@ResponseStatus(code = HttpStatus.GATEWAY_TIMEOUT, reason = "gateway.timeout")
public void handleException(SocketTimeoutException ex) {

}
}

@Configuration
static class MyConfig {
Expand All @@ -543,6 +581,11 @@ public TestExceptionResolver testExceptionResolver() {
public AnotherTestExceptionResolver anotherTestExceptionResolver() {
return new AnotherTestExceptionResolver();
}

@Bean
public ResponseStatusTestExceptionResolver responseStatusTestExceptionResolver() {
return new ResponseStatusTestExceptionResolver();
}
}


Expand Down