Browse Source

Use MessageSource in HandlerMethod for error reason

Closes gh-27156
pull/27165/head
Rossen Stoyanchev 5 years ago
parent
commit
bb816c123c
  1. 30
      spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java
  2. 4
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/AbstractHandlerMethodMapping.java
  3. 4
      spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java
  4. 44
      spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethodTests.java

30
spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -29,6 +29,8 @@ import org.apache.commons.logging.Log; @@ -29,6 +29,8 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
@ -70,6 +72,9 @@ public class HandlerMethod { @@ -70,6 +72,9 @@ public class HandlerMethod {
@Nullable
private final BeanFactory beanFactory;
@Nullable
private final MessageSource messageSource;
private final Class<?> beanType;
private final Method method;
@ -101,6 +106,7 @@ public class HandlerMethod { @@ -101,6 +106,7 @@ public class HandlerMethod {
Assert.notNull(method, "Method is required");
this.bean = bean;
this.beanFactory = null;
this.messageSource = null;
this.beanType = ClassUtils.getUserClass(bean);
this.method = method;
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
@ -118,6 +124,7 @@ public class HandlerMethod { @@ -118,6 +124,7 @@ public class HandlerMethod {
Assert.notNull(methodName, "Method name is required");
this.bean = bean;
this.beanFactory = null;
this.messageSource = null;
this.beanType = ClassUtils.getUserClass(bean);
this.method = bean.getClass().getMethod(methodName, parameterTypes);
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(this.method);
@ -132,11 +139,23 @@ public class HandlerMethod { @@ -132,11 +139,23 @@ public class HandlerMethod {
* re-create the {@code HandlerMethod} with an initialized bean.
*/
public HandlerMethod(String beanName, BeanFactory beanFactory, Method method) {
this(beanName, beanFactory, null, method);
}
/**
* Variant of {@link #HandlerMethod(String, BeanFactory, Method)} that
* also accepts a {@link MessageSource}.
*/
public HandlerMethod(
String beanName, BeanFactory beanFactory,
@Nullable MessageSource messageSource, Method method) {
Assert.hasText(beanName, "Bean name is required");
Assert.notNull(beanFactory, "BeanFactory is required");
Assert.notNull(method, "Method is required");
this.bean = beanName;
this.beanFactory = beanFactory;
this.messageSource = messageSource;
Class<?> beanType = beanFactory.getType(beanName);
if (beanType == null) {
throw new IllegalStateException("Cannot resolve bean type for bean with name '" + beanName + "'");
@ -156,6 +175,7 @@ public class HandlerMethod { @@ -156,6 +175,7 @@ public class HandlerMethod {
Assert.notNull(handlerMethod, "HandlerMethod is required");
this.bean = handlerMethod.bean;
this.beanFactory = handlerMethod.beanFactory;
this.messageSource = handlerMethod.messageSource;
this.beanType = handlerMethod.beanType;
this.method = handlerMethod.method;
this.bridgedMethod = handlerMethod.bridgedMethod;
@ -174,6 +194,7 @@ public class HandlerMethod { @@ -174,6 +194,7 @@ public class HandlerMethod {
Assert.notNull(handler, "Handler object is required");
this.bean = handler;
this.beanFactory = handlerMethod.beanFactory;
this.messageSource = handlerMethod.messageSource;
this.beanType = handlerMethod.beanType;
this.method = handlerMethod.method;
this.bridgedMethod = handlerMethod.bridgedMethod;
@ -199,8 +220,13 @@ public class HandlerMethod { @@ -199,8 +220,13 @@ public class HandlerMethod {
annotation = AnnotatedElementUtils.findMergedAnnotation(getBeanType(), ResponseStatus.class);
}
if (annotation != null) {
String reason = annotation.reason();
String resolvedReason = (StringUtils.hasText(reason) && this.messageSource != null ?
this.messageSource.getMessage(reason, null, reason, LocaleContextHolder.getLocale()) :
reason);
this.responseStatus = annotation.code();
this.responseStatusReason = annotation.reason();
this.responseStatusReason = resolvedReason;
}
}

4
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/AbstractHandlerMethodMapping.java

@ -258,7 +258,9 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap @@ -258,7 +258,9 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
protected HandlerMethod createHandlerMethod(Object handler, Method method) {
if (handler instanceof String) {
return new HandlerMethod((String) handler,
obtainApplicationContext().getAutowireCapableBeanFactory(), method);
obtainApplicationContext().getAutowireCapableBeanFactory(),
obtainApplicationContext(),
method);
}
return new HandlerMethod(handler, method);
}

4
spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java

@ -337,7 +337,9 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap @@ -337,7 +337,9 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
protected HandlerMethod createHandlerMethod(Object handler, Method method) {
if (handler instanceof String) {
return new HandlerMethod((String) handler,
obtainApplicationContext().getAutowireCapableBeanFactory(), method);
obtainApplicationContext().getAutowireCapableBeanFactory(),
obtainApplicationContext(),
method);
}
return new HandlerMethod(handler, method);
}

44
spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethodTests.java

@ -22,6 +22,7 @@ import java.lang.reflect.Method; @@ -22,6 +22,7 @@ import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletResponse;
@ -29,6 +30,9 @@ import javax.servlet.http.HttpServletResponse; @@ -29,6 +30,9 @@ import javax.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Flux;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AliasFor;
@ -47,12 +51,14 @@ import org.springframework.web.context.request.NativeWebRequest; @@ -47,12 +51,14 @@ import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.filter.ShallowEtagHeaderFilter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.annotation.RequestParamMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodArgumentResolverComposite;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.view.RedirectView;
import org.springframework.web.testfixture.method.ResolvableMethod;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
@ -180,6 +186,39 @@ public class ServletInvocableHandlerMethodTests { @@ -180,6 +186,39 @@ public class ServletInvocableHandlerMethodTests {
.as("When a status reason w/ used, the request is handled").isTrue();
}
@Test
public void invokeAndHandle_responseStatusAndReasonCode() throws Exception {
Locale locale = Locale.ENGLISH;
String beanName = "handler";
StaticApplicationContext context = new StaticApplicationContext();
context.registerBean(beanName, Handler.class);
context.addMessage("BadRequest.error", locale, "Bad request message");
context.refresh();
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
System.out.println(beanFactory.getType(beanName));
LocaleContextHolder.setLocale(locale);
try {
Method method = ResolvableMethod.on(Handler.class)
.named("responseStatusWithReasonCode")
.resolveMethod();
HandlerMethod handlerMethod = new HandlerMethod(beanName, beanFactory, context, method);
handlerMethod = handlerMethod.createWithResolvedBean();
new ServletInvocableHandlerMethod(handlerMethod)
.invokeAndHandle(this.webRequest, this.mavContainer);
}
finally {
LocaleContextHolder.resetLocaleContext();
}
assertThat(this.response.getStatus()).isEqualTo(HttpStatus.BAD_REQUEST.value());
assertThat(this.response.getErrorMessage()).isEqualTo("Bad request message");
}
@Test // gh-23775, gh-24635
public void invokeAndHandle_ETagFilterHasNoImpactWhenETagPresent() throws Exception {
@ -417,6 +456,11 @@ public class ServletInvocableHandlerMethodTests { @@ -417,6 +456,11 @@ public class ServletInvocableHandlerMethodTests {
return "foo";
}
@ResponseStatus(code = HttpStatus.BAD_REQUEST, reason = "BadRequest.error")
public String responseStatusWithReasonCode() {
return "foo";
}
@ComposedResponseStatus(responseStatus = HttpStatus.BAD_REQUEST)
public void composedResponseStatus() {
}

Loading…
Cancel
Save