diff --git a/spring-web/src/main/java/org/springframework/http/HttpStatus.java b/spring-web/src/main/java/org/springframework/http/HttpStatus.java index 3a2a23cada0..015a2969cbe 100644 --- a/spring-web/src/main/java/org/springframework/http/HttpStatus.java +++ b/spring-web/src/main/java/org/springframework/http/HttpStatus.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -392,17 +392,17 @@ public enum HttpStatus { NETWORK_AUTHENTICATION_REQUIRED(511, "Network Authentication Required"); - private final int value; private final String reasonPhrase; - private HttpStatus(int value, String reasonPhrase) { + HttpStatus(int value, String reasonPhrase) { this.value = value; this.reasonPhrase = reasonPhrase; } + /** * Return the integer value of this status code. */ @@ -414,7 +414,7 @@ public enum HttpStatus { * Return the reason phrase of this status code. */ public String getReasonPhrase() { - return reasonPhrase; + return this.reasonPhrase; } /** @@ -423,7 +423,7 @@ public enum HttpStatus { * This is a shortcut for checking the value of {@link #series()}. */ public boolean is1xxInformational() { - return (Series.INFORMATIONAL.equals(series())); + return Series.INFORMATIONAL.equals(series()); } /** @@ -432,7 +432,7 @@ public enum HttpStatus { * This is a shortcut for checking the value of {@link #series()}. */ public boolean is2xxSuccessful() { - return (Series.SUCCESSFUL.equals(series())); + return Series.SUCCESSFUL.equals(series()); } /** @@ -441,7 +441,7 @@ public enum HttpStatus { * This is a shortcut for checking the value of {@link #series()}. */ public boolean is3xxRedirection() { - return (Series.REDIRECTION.equals(series())); + return Series.REDIRECTION.equals(series()); } @@ -451,7 +451,7 @@ public enum HttpStatus { * This is a shortcut for checking the value of {@link #series()}. */ public boolean is4xxClientError() { - return (Series.CLIENT_ERROR.equals(series())); + return Series.CLIENT_ERROR.equals(series()); } /** @@ -460,7 +460,7 @@ public enum HttpStatus { * This is a shortcut for checking the value of {@link #series()}. */ public boolean is5xxServerError() { - return (Series.SERVER_ERROR.equals(series())); + return Series.SERVER_ERROR.equals(series()); } /** @@ -476,7 +476,7 @@ public enum HttpStatus { */ @Override public String toString() { - return Integer.toString(value); + return Integer.toString(this.value); } @@ -497,10 +497,10 @@ public enum HttpStatus { /** - * Java 5 enumeration of HTTP status series. + * Enumeration of HTTP status series. *

Retrievable via {@link HttpStatus#series()}. */ - public static enum Series { + public enum Series { INFORMATIONAL(1), SUCCESSFUL(2), @@ -510,7 +510,7 @@ public enum HttpStatus { private final int value; - private Series(int value) { + Series(int value) { this.value = value; } @@ -534,7 +534,6 @@ public enum HttpStatus { public static Series valueOf(HttpStatus status) { return valueOf(status.value); } - } } diff --git a/spring-web/src/main/java/org/springframework/http/ResponseEntity.java b/spring-web/src/main/java/org/springframework/http/ResponseEntity.java index 519d28798ad..7edb9ea2925 100644 --- a/spring-web/src/main/java/org/springframework/http/ResponseEntity.java +++ b/spring-web/src/main/java/org/springframework/http/ResponseEntity.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.LinkedHashSet; import java.util.Set; +import org.springframework.util.Assert; import org.springframework.util.MultiValueMap; import org.springframework.util.ObjectUtils; @@ -65,45 +66,55 @@ import org.springframework.util.ObjectUtils; */ public class ResponseEntity extends HttpEntity { - private final HttpStatus statusCode; + private final Object statusCode; /** * Create a new {@code ResponseEntity} with the given status code, and no body nor headers. - * @param statusCode the status code + * @param status the status code */ - public ResponseEntity(HttpStatus statusCode) { - super(); - this.statusCode = statusCode; + public ResponseEntity(HttpStatus status) { + this(null, null, status); } /** * Create a new {@code ResponseEntity} with the given body and status code, and no headers. * @param body the entity body - * @param statusCode the status code + * @param status the status code */ - public ResponseEntity(T body, HttpStatus statusCode) { - super(body); - this.statusCode = statusCode; + public ResponseEntity(T body, HttpStatus status) { + this(body, null, status); } /** * Create a new {@code HttpEntity} with the given headers and status code, and no body. * @param headers the entity headers - * @param statusCode the status code + * @param status the status code */ - public ResponseEntity(MultiValueMap headers, HttpStatus statusCode) { - super(headers); - this.statusCode = statusCode; + public ResponseEntity(MultiValueMap headers, HttpStatus status) { + this(null, headers, status); } /** * Create a new {@code HttpEntity} with the given body, headers, and status code. * @param body the entity body * @param headers the entity headers - * @param statusCode the status code + * @param status the status code */ - public ResponseEntity(T body, MultiValueMap headers, HttpStatus statusCode) { + public ResponseEntity(T body, MultiValueMap headers, HttpStatus status) { + super(body, headers); + Assert.notNull(status, "HttpStatus must not be null"); + this.statusCode = status; + } + + /** + * Create a new {@code HttpEntity} with the given body, headers, and status code. + * Just used behind the nested builder API. + * @param body the entity body + * @param headers the entity headers + * @param statusCode the status code (as {@code HttpStatus} or as {@code Integer} value) + */ + private ResponseEntity(T body, MultiValueMap headers, Object statusCode) { super(body, headers); this.statusCode = statusCode; } @@ -111,10 +122,29 @@ public class ResponseEntity extends HttpEntity { /** * Return the HTTP status code of the response. - * @return the HTTP status as an HttpStatus enum value + * @return the HTTP status as an HttpStatus enum entry */ public HttpStatus getStatusCode() { - return this.statusCode; + if (this.statusCode instanceof HttpStatus) { + return (HttpStatus) this.statusCode; + } + else { + return HttpStatus.valueOf((Integer) this.statusCode); + } + } + + /** + * Return the HTTP status code of the response. + * @return the HTTP status as an int value + * @since 4.3 + */ + public int getStatusCodeValue() { + if (this.statusCode instanceof HttpStatus) { + return ((HttpStatus) this.statusCode).value(); + } + else { + return (Integer) this.statusCode; + } } @@ -139,8 +169,10 @@ public class ResponseEntity extends HttpEntity { public String toString() { StringBuilder builder = new StringBuilder("<"); builder.append(this.statusCode.toString()); - builder.append(' '); - builder.append(this.statusCode.getReasonPhrase()); + if (this.statusCode instanceof HttpStatus) { + builder.append(' '); + builder.append(((HttpStatus) this.statusCode).getReasonPhrase()); + } builder.append(','); T body = getBody(); HttpHeaders headers = getHeaders(); @@ -167,6 +199,7 @@ public class ResponseEntity extends HttpEntity { * @since 4.1 */ public static BodyBuilder status(HttpStatus status) { + Assert.notNull(status, "HttpStatus must not be null"); return new DefaultBuilder(status); } @@ -177,7 +210,7 @@ public class ResponseEntity extends HttpEntity { * @since 4.1 */ public static BodyBuilder status(int status) { - return status(HttpStatus.valueOf(status)); + return new DefaultBuilder(status); } /** @@ -388,12 +421,12 @@ public class ResponseEntity extends HttpEntity { private static class DefaultBuilder implements BodyBuilder { - private final HttpStatus status; + private final Object statusCode; private final HttpHeaders headers = new HttpHeaders(); - public DefaultBuilder(HttpStatus status) { - this.status = status; + public DefaultBuilder(Object statusCode) { + this.statusCode = statusCode; } @Override @@ -473,12 +506,12 @@ public class ResponseEntity extends HttpEntity { @Override public ResponseEntity build() { - return new ResponseEntity(null, this.headers, this.status); + return body(null); } @Override public ResponseEntity body(T body) { - return new ResponseEntity(body, this.headers, this.status); + return new ResponseEntity(body, this.headers, this.statusCode); } } diff --git a/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java b/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java index b4f4369f511..5944297feb3 100644 --- a/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java +++ b/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -73,6 +73,7 @@ public class ServletServerHttpResponse implements ServerHttpResponse { @Override public void setStatusCode(HttpStatus status) { + Assert.notNull(status, "HttpStatus must not be null"); this.servletResponse.setStatus(status.value()); } diff --git a/spring-web/src/test/java/org/springframework/http/ResponseEntityTests.java b/spring-web/src/test/java/org/springframework/http/ResponseEntityTests.java index dca351a41cc..5bc9d3f794a 100644 --- a/spring-web/src/test/java/org/springframework/http/ResponseEntityTests.java +++ b/spring-web/src/test/java/org/springframework/http/ResponseEntityTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -252,4 +252,22 @@ public class ResponseEntityTests { assertThat(cacheControlHeader, Matchers.equalTo("no-store")); } + @Test + public void statusCodeAsInt() { + Integer entity = new Integer(42); + ResponseEntity responseEntity = ResponseEntity.status(200).body(entity); + + assertEquals(200, responseEntity.getStatusCode().value()); + assertEquals(entity, responseEntity.getBody()); + } + + @Test + public void customStatusCode() { + Integer entity = new Integer(42); + ResponseEntity responseEntity = ResponseEntity.status(299).body(entity); + + assertEquals(299, responseEntity.getStatusCodeValue()); + assertEquals(entity, responseEntity.getBody()); + } + } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/HttpEntityMethodProcessor.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/HttpEntityMethodProcessor.java index 5041acfc97d..b3913d79588 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/HttpEntityMethodProcessor.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/HttpEntityMethodProcessor.java @@ -184,9 +184,8 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro } } - Object body = responseEntity.getBody(); if (responseEntity instanceof ResponseEntity) { - outputMessage.setStatusCode(((ResponseEntity) responseEntity).getStatusCode()); + outputMessage.getServletResponse().setStatus(((ResponseEntity) responseEntity).getStatusCodeValue()); HttpMethod method = inputMessage.getMethod(); boolean isGetOrHead = (HttpMethod.GET == method || HttpMethod.HEAD == method); if (isGetOrHead && isResourceNotModified(inputMessage, outputMessage)) { @@ -197,6 +196,8 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro return; } } + + Object body = responseEntity.getBody(); if (inputMessage.getHeaders().containsKey(HttpHeaders.RANGE) && Resource.class.isAssignableFrom(body.getClass())) { try { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandler.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandler.java index 8d07222a171..7930819c8a2 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandler.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandler.java @@ -130,9 +130,9 @@ public class ResponseBodyEmitterReturnValueHandler implements AsyncHandlerMethod HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); ServerHttpResponse outputMessage = new ServletServerHttpResponse(response); - if (ResponseEntity.class.isAssignableFrom(returnValue.getClass())) { + if (returnValue instanceof ResponseEntity) { ResponseEntity responseEntity = (ResponseEntity) returnValue; - outputMessage.setStatusCode(responseEntity.getStatusCode()); + response.setStatus(responseEntity.getStatusCodeValue()); outputMessage.getHeaders().putAll(responseEntity.getHeaders()); returnValue = responseEntity.getBody(); if (returnValue == null) { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/StreamingResponseBodyReturnValueHandler.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/StreamingResponseBodyReturnValueHandler.java index 40852899cb0..63c37bea4c7 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/StreamingResponseBodyReturnValueHandler.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/StreamingResponseBodyReturnValueHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.web.servlet.mvc.method.annotation; import java.io.OutputStream; import java.util.concurrent.Callable; - import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletResponse; @@ -33,7 +33,6 @@ import org.springframework.web.filter.ShallowEtagHeaderFilter; import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.method.support.ModelAndViewContainer; - /** * Supports return values of type * {@link org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody} @@ -68,11 +67,10 @@ public class StreamingResponseBodyReturnValueHandler implements HandlerMethodRet HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); ServerHttpResponse outputMessage = new ServletServerHttpResponse(response); - if (ResponseEntity.class.isAssignableFrom(returnValue.getClass())) { + if (returnValue instanceof ResponseEntity) { ResponseEntity responseEntity = (ResponseEntity) returnValue; - outputMessage.setStatusCode(responseEntity.getStatusCode()); + response.setStatus(responseEntity.getStatusCodeValue()); outputMessage.getHeaders().putAll(responseEntity.getHeaders()); - returnValue = responseEntity.getBody(); if (returnValue == null) { mavContainer.setRequestHandled(true); @@ -97,7 +95,6 @@ public class StreamingResponseBodyReturnValueHandler implements HandlerMethodRet private final StreamingResponseBody streamingBody; - public StreamingResponseBodyTask(OutputStream outputStream, StreamingResponseBody streamingBody) { this.outputStream = outputStream; this.streamingBody = streamingBody;