Skip to content

Commit 597fe07

Browse files
committed
HandlerMethod evaluates ResponseStatus annotation for early caching
Issue: SPR-15227 (cherry picked from commit 5986f88)
1 parent 8321f01 commit 597fe07

File tree

3 files changed

+79
-64
lines changed

3 files changed

+79
-64
lines changed

spring-messaging/src/main/java/org/springframework/messaging/handler/HandlerMethod.java

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public class HandlerMethod {
6464

6565
private final MethodParameter[] parameters;
6666

67-
private final HandlerMethod resolvedFromHandlerMethod;
67+
private HandlerMethod resolvedFromHandlerMethod;
6868

6969

7070
/**
@@ -79,7 +79,6 @@ public HandlerMethod(Object bean, Method method) {
7979
this.method = method;
8080
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
8181
this.parameters = initMethodParameters();
82-
this.resolvedFromHandlerMethod = null;
8382
}
8483

8584
/**
@@ -95,7 +94,6 @@ public HandlerMethod(Object bean, String methodName, Class<?>... parameterTypes)
9594
this.method = bean.getClass().getMethod(methodName, parameterTypes);
9695
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(this.method);
9796
this.parameters = initMethodParameters();
98-
this.resolvedFromHandlerMethod = null;
9997
}
10098

10199
/**
@@ -113,7 +111,6 @@ public HandlerMethod(String beanName, BeanFactory beanFactory, Method method) {
113111
this.method = method;
114112
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
115113
this.parameters = initMethodParameters();
116-
this.resolvedFromHandlerMethod = null;
117114
}
118115

119116
/**
@@ -158,14 +155,14 @@ private MethodParameter[] initMethodParameters() {
158155
}
159156

160157
/**
161-
* Returns the bean for this handler method.
158+
* Return the bean for this handler method.
162159
*/
163160
public Object getBean() {
164161
return this.bean;
165162
}
166163

167164
/**
168-
* Returns the method for this handler method.
165+
* Return the method for this handler method.
169166
*/
170167
public Method getMethod() {
171168
return this.method;
@@ -189,21 +186,12 @@ protected Method getBridgedMethod() {
189186
}
190187

191188
/**
192-
* Returns the method parameters for this handler method.
189+
* Return the method parameters for this handler method.
193190
*/
194191
public MethodParameter[] getMethodParameters() {
195192
return this.parameters;
196193
}
197194

198-
/**
199-
* Return the HandlerMethod from which this HandlerMethod instance was
200-
* resolved via {@link #createWithResolvedBean()}.
201-
* @since 4.3
202-
*/
203-
public HandlerMethod getResolvedFromHandlerMethod() {
204-
return this.resolvedFromHandlerMethod;
205-
}
206-
207195
/**
208196
* Return the HandlerMethod return type.
209197
*/
@@ -219,14 +207,14 @@ public MethodParameter getReturnValueType(Object returnValue) {
219207
}
220208

221209
/**
222-
* Returns {@code true} if the method return type is void, {@code false} otherwise.
210+
* Return {@code true} if the method return type is void, {@code false} otherwise.
223211
*/
224212
public boolean isVoid() {
225213
return Void.TYPE.equals(getReturnType().getParameterType());
226214
}
227215

228216
/**
229-
* Returns a single annotation on the underlying method traversing its super methods
217+
* Return a single annotation on the underlying method traversing its super methods
230218
* if no annotation can be found on the given method itself.
231219
* <p>Also supports <em>merged</em> composed annotations with attribute
232220
* overrides as of Spring Framework 4.3.
@@ -248,6 +236,15 @@ public <A extends Annotation> boolean hasMethodAnnotation(Class<A> annotationTyp
248236
return AnnotatedElementUtils.hasAnnotation(this.method, annotationType);
249237
}
250238

239+
/**
240+
* Return the HandlerMethod from which this HandlerMethod instance was
241+
* resolved via {@link #createWithResolvedBean()}.
242+
* @since 4.3
243+
*/
244+
public HandlerMethod getResolvedFromHandlerMethod() {
245+
return this.resolvedFromHandlerMethod;
246+
}
247+
251248
/**
252249
* If the provided instance contains a bean name rather than an object instance,
253250
* the bean name is resolved before a {@link HandlerMethod} is created and returned.

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

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@
2828
import org.springframework.core.MethodParameter;
2929
import org.springframework.core.annotation.AnnotatedElementUtils;
3030
import org.springframework.core.annotation.SynthesizingMethodParameter;
31+
import org.springframework.http.HttpStatus;
3132
import org.springframework.util.Assert;
3233
import org.springframework.util.ClassUtils;
34+
import org.springframework.web.bind.annotation.ResponseStatus;
3335

3436
/**
3537
* Encapsulates information about a handler method consisting of a
@@ -65,7 +67,11 @@ public class HandlerMethod {
6567

6668
private final MethodParameter[] parameters;
6769

68-
private final HandlerMethod resolvedFromHandlerMethod;
70+
private HttpStatus responseStatus;
71+
72+
private String responseStatusReason;
73+
74+
private HandlerMethod resolvedFromHandlerMethod;
6975

7076

7177
/**
@@ -80,7 +86,7 @@ public HandlerMethod(Object bean, Method method) {
8086
this.method = method;
8187
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
8288
this.parameters = initMethodParameters();
83-
this.resolvedFromHandlerMethod = null;
89+
evaluateResponseStatus();
8490
}
8591

8692
/**
@@ -96,7 +102,7 @@ public HandlerMethod(Object bean, String methodName, Class<?>... parameterTypes)
96102
this.method = bean.getClass().getMethod(methodName, parameterTypes);
97103
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(this.method);
98104
this.parameters = initMethodParameters();
99-
this.resolvedFromHandlerMethod = null;
105+
evaluateResponseStatus();
100106
}
101107

102108
/**
@@ -114,7 +120,7 @@ public HandlerMethod(String beanName, BeanFactory beanFactory, Method method) {
114120
this.method = method;
115121
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
116122
this.parameters = initMethodParameters();
117-
this.resolvedFromHandlerMethod = null;
123+
evaluateResponseStatus();
118124
}
119125

120126
/**
@@ -128,6 +134,8 @@ protected HandlerMethod(HandlerMethod handlerMethod) {
128134
this.method = handlerMethod.method;
129135
this.bridgedMethod = handlerMethod.bridgedMethod;
130136
this.parameters = handlerMethod.parameters;
137+
this.responseStatus = handlerMethod.responseStatus;
138+
this.responseStatusReason = handlerMethod.responseStatusReason;
131139
this.resolvedFromHandlerMethod = handlerMethod.resolvedFromHandlerMethod;
132140
}
133141

@@ -143,6 +151,8 @@ private HandlerMethod(HandlerMethod handlerMethod, Object handler) {
143151
this.method = handlerMethod.method;
144152
this.bridgedMethod = handlerMethod.bridgedMethod;
145153
this.parameters = handlerMethod.parameters;
154+
this.responseStatus = handlerMethod.responseStatus;
155+
this.responseStatusReason = handlerMethod.responseStatusReason;
146156
this.resolvedFromHandlerMethod = handlerMethod;
147157
}
148158

@@ -158,15 +168,27 @@ private MethodParameter[] initMethodParameters() {
158168
return result;
159169
}
160170

171+
private void evaluateResponseStatus() {
172+
ResponseStatus annotation = getMethodAnnotation(ResponseStatus.class);
173+
if (annotation == null) {
174+
annotation = AnnotatedElementUtils.findMergedAnnotation(getBeanType(), ResponseStatus.class);
175+
}
176+
if (annotation != null) {
177+
this.responseStatus = annotation.code();
178+
this.responseStatusReason = annotation.reason();
179+
}
180+
}
181+
182+
161183
/**
162-
* Returns the bean for this handler method.
184+
* Return the bean for this handler method.
163185
*/
164186
public Object getBean() {
165187
return this.bean;
166188
}
167189

168190
/**
169-
* Returns the method for this handler method.
191+
* Return the method for this handler method.
170192
*/
171193
public Method getMethod() {
172194
return this.method;
@@ -190,18 +212,28 @@ protected Method getBridgedMethod() {
190212
}
191213

192214
/**
193-
* Returns the method parameters for this handler method.
215+
* Return the method parameters for this handler method.
194216
*/
195217
public MethodParameter[] getMethodParameters() {
196218
return this.parameters;
197219
}
198220

199221
/**
200-
* Return the HandlerMethod from which this HandlerMethod instance was
201-
* resolved via {@link #createWithResolvedBean()}.
222+
* Return the specified response status, if any.
223+
* @since 4.3.8
224+
* @see ResponseStatus#code()
202225
*/
203-
public HandlerMethod getResolvedFromHandlerMethod() {
204-
return this.resolvedFromHandlerMethod;
226+
protected HttpStatus getResponseStatus() {
227+
return this.responseStatus;
228+
}
229+
230+
/**
231+
* Return the associated response status reason, if any.
232+
* @since 4.3.8
233+
* @see ResponseStatus#reason()
234+
*/
235+
protected String getResponseStatusReason() {
236+
return this.responseStatusReason;
205237
}
206238

207239
/**
@@ -219,14 +251,14 @@ public MethodParameter getReturnValueType(Object returnValue) {
219251
}
220252

221253
/**
222-
* Returns {@code true} if the method return type is void, {@code false} otherwise.
254+
* Return {@code true} if the method return type is void, {@code false} otherwise.
223255
*/
224256
public boolean isVoid() {
225257
return Void.TYPE.equals(getReturnType().getParameterType());
226258
}
227259

228260
/**
229-
* Returns a single annotation on the underlying method traversing its super methods
261+
* Return a single annotation on the underlying method traversing its super methods
230262
* if no annotation can be found on the given method itself.
231263
* <p>Also supports <em>merged</em> composed annotations with attribute
232264
* overrides as of Spring Framework 4.2.2.
@@ -248,6 +280,14 @@ public <A extends Annotation> boolean hasMethodAnnotation(Class<A> annotationTyp
248280
return AnnotatedElementUtils.hasAnnotation(this.method, annotationType);
249281
}
250282

283+
/**
284+
* Return the HandlerMethod from which this HandlerMethod instance was
285+
* resolved via {@link #createWithResolvedBean()}.
286+
*/
287+
public HandlerMethod getResolvedFromHandlerMethod() {
288+
return this.resolvedFromHandlerMethod;
289+
}
290+
251291
/**
252292
* If the provided instance contains a bean name rather than an object instance,
253293
* the bean name is resolved before a {@link HandlerMethod} is created and returned.

spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424

2525
import org.springframework.core.MethodParameter;
2626
import org.springframework.core.ResolvableType;
27-
import org.springframework.core.annotation.AnnotatedElementUtils;
2827
import org.springframework.http.HttpStatus;
2928
import org.springframework.util.ClassUtils;
3029
import org.springframework.util.StringUtils;
@@ -58,11 +57,6 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
5857

5958
private static final Method CALLABLE_METHOD = ClassUtils.getMethod(Callable.class, "call");
6059

61-
62-
private HttpStatus responseStatus;
63-
64-
private String responseReason;
65-
6660
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
6761

6862

@@ -71,29 +65,16 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
7165
*/
7266
public ServletInvocableHandlerMethod(Object handler, Method method) {
7367
super(handler, method);
74-
initResponseStatus();
7568
}
7669

7770
/**
7871
* Create an instance from a {@code HandlerMethod}.
7972
*/
8073
public ServletInvocableHandlerMethod(HandlerMethod handlerMethod) {
8174
super(handlerMethod);
82-
initResponseStatus();
8375
}
8476

8577

86-
private void initResponseStatus() {
87-
ResponseStatus annotation = getMethodAnnotation(ResponseStatus.class);
88-
if (annotation == null) {
89-
annotation = AnnotatedElementUtils.findMergedAnnotation(getBeanType(), ResponseStatus.class);
90-
}
91-
if (annotation != null) {
92-
this.responseStatus = annotation.code();
93-
this.responseReason = annotation.reason();
94-
}
95-
}
96-
9778
/**
9879
* Register {@link HandlerMethodReturnValueHandler} instances to use to
9980
* handle return values.
@@ -117,12 +98,12 @@ public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer
11798
setResponseStatus(webRequest);
11899

119100
if (returnValue == null) {
120-
if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
101+
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
121102
mavContainer.setRequestHandled(true);
122103
return;
123104
}
124105
}
125-
else if (StringUtils.hasText(this.responseReason)) {
106+
else if (StringUtils.hasText(getResponseStatusReason())) {
126107
mavContainer.setRequestHandled(true);
127108
return;
128109
}
@@ -144,17 +125,21 @@ else if (StringUtils.hasText(this.responseReason)) {
144125
* Set the response status according to the {@link ResponseStatus} annotation.
145126
*/
146127
private void setResponseStatus(ServletWebRequest webRequest) throws IOException {
147-
if (this.responseStatus == null) {
128+
HttpStatus status = getResponseStatus();
129+
if (status == null) {
148130
return;
149131
}
150-
if (StringUtils.hasText(this.responseReason)) {
151-
webRequest.getResponse().sendError(this.responseStatus.value(), this.responseReason);
132+
133+
String reason = getResponseStatusReason();
134+
if (StringUtils.hasText(reason)) {
135+
webRequest.getResponse().sendError(status.value(), reason);
152136
}
153137
else {
154-
webRequest.getResponse().setStatus(this.responseStatus.value());
138+
webRequest.getResponse().setStatus(status.value());
155139
}
140+
156141
// To be picked up by RedirectView
157-
webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, this.responseStatus);
142+
webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status);
158143
}
159144

160145
/**
@@ -166,13 +151,6 @@ private boolean isRequestNotModified(ServletWebRequest webRequest) {
166151
return webRequest.isNotModified();
167152
}
168153

169-
/**
170-
* Does this method have the response status instruction?
171-
*/
172-
private boolean hasResponseStatus() {
173-
return (this.responseStatus != null);
174-
}
175-
176154
private String getReturnValueHandlingErrorMessage(String message, Object returnValue) {
177155
StringBuilder sb = new StringBuilder(message);
178156
if (returnValue != null) {

0 commit comments

Comments
 (0)