From 547342b27d39efdb7ef6de068897b972e85c7b23 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Thu, 30 Jan 2020 10:06:58 +0000 Subject: [PATCH] Status code as Integer methods in ServerHttpResponse Closes gh-24400 --- .../reactive/server/HttpHandlerConnector.java | 4 +- .../reactive/AbstractServerHttpResponse.java | 25 ++++++++- .../reactive/ReactorServerHttpResponse.java | 17 ++++--- .../server/reactive/ServerHttpResponse.java | 51 ++++++++++++++++--- .../reactive/ServletServerHttpResponse.java | 18 ++++--- .../reactive/UndertowServerHttpResponse.java | 17 ++++--- .../server/DefaultServerResponseBuilder.java | 15 +----- .../ResponseEntityResultHandler.java | 14 ++--- 8 files changed, 108 insertions(+), 53 deletions(-) diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/HttpHandlerConnector.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/HttpHandlerConnector.java index c5841c41ec..ee23babdc4 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/HttpHandlerConnector.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/HttpHandlerConnector.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 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. @@ -135,7 +135,7 @@ public class HttpHandlerConnector implements ClientHttpConnector { } private ClientHttpResponse adaptResponse(MockServerHttpResponse response, Flux body) { - Integer status = response.getStatusCodeValue(); + Integer status = response.getRawStatusCode(); MockClientHttpResponse clientResponse = new MockClientHttpResponse((status != null) ? status : 200); clientResponse.getHeaders().putAll(response.getHeaders()); clientResponse.getCookies().putAll(response.getCookies()); diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractServerHttpResponse.java b/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractServerHttpResponse.java index f4841a7052..b6c7f98037 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractServerHttpResponse.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractServerHttpResponse.java @@ -111,21 +111,44 @@ public abstract class AbstractServerHttpResponse implements ServerHttpResponse { return (this.statusCode != null ? HttpStatus.resolve(this.statusCode) : null); } + @Override + public boolean setRawStatusCode(@Nullable Integer statusCode) { + if (this.state.get() == State.COMMITTED) { + return false; + } + else { + this.statusCode = statusCode; + return true; + } + } + + @Override + @Nullable + public Integer getRawStatusCode() { + return this.statusCode; + } + /** * Set the HTTP status code of the response. * @param statusCode the HTTP status as an integer value * @since 5.0.1 + * @deprecated as of 5.2.4 in favor of {@link ServerHttpResponse#setRawStatusCode(Integer)}. */ + @Deprecated public void setStatusCodeValue(@Nullable Integer statusCode) { - this.statusCode = statusCode; + if (this.state.get() != State.COMMITTED) { + this.statusCode = statusCode; + } } /** * Return the HTTP status code of the response. * @return the HTTP status as an integer value * @since 5.0.1 + * @deprecated as of 5.2.4 in favor of {@link ServerHttpResponse#getRawStatusCode()}. */ @Nullable + @Deprecated public Integer getStatusCodeValue() { return this.statusCode; } diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorServerHttpResponse.java b/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorServerHttpResponse.java index 43842bdb28..64b0a1c3f1 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorServerHttpResponse.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorServerHttpResponse.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 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. @@ -61,16 +61,21 @@ class ReactorServerHttpResponse extends AbstractServerHttpResponse implements Ze @Override public HttpStatus getStatusCode() { - HttpStatus httpStatus = super.getStatusCode(); - return (httpStatus != null ? httpStatus : HttpStatus.resolve(this.response.status().code())); + HttpStatus status = super.getStatusCode(); + return (status != null ? status : HttpStatus.resolve(this.response.status().code())); } + @Override + public Integer getRawStatusCode() { + Integer status = super.getRawStatusCode(); + return (status != null ? status : this.response.status().code()); + } @Override protected void applyStatusCode() { - Integer statusCode = getStatusCodeValue(); - if (statusCode != null) { - this.response.status(statusCode); + Integer status = super.getRawStatusCode(); + if (status != null) { + this.response.status(status); } } diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpResponse.java b/spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpResponse.java index 2bbfba900f..eb665e362e 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpResponse.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpResponse.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 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. @@ -27,6 +27,7 @@ import org.springframework.util.MultiValueMap; * * @author Arjen Poutsma * @author Sebastien Deleuze + * @author Rossen Stoyanchev * @since 5.0 */ public interface ServerHttpResponse extends ReactiveHttpOutputMessage { @@ -34,21 +35,55 @@ public interface ServerHttpResponse extends ReactiveHttpOutputMessage { /** * Set the HTTP status code of the response. * @param status the HTTP status as an {@link HttpStatus} enum value - * @return {@code false} if the status code has not been set because the - * HTTP response is already committed, {@code true} if successfully set. + * @return {@code false} if the status code change wasn't processed because + * the HTTP response is committed, {@code true} if successfully set. */ boolean setStatusCode(@Nullable HttpStatus status); /** - * Return the status code set via {@link #setStatusCode}, or if the status - * has not been set, return the default status code from the underlying - * server response. The return value may be {@code null} if the status code - * value is outside the {@link HttpStatus} enum range, or if the underlying - * server response does not have a default value. + * Return the status code that has been set, or otherwise fall back on the + * status of the response from the underlying server. The return value may + * be {@code null} if the status code value is outside the + * {@link HttpStatus} enum range, or if there is no default value from the + * underlying server. */ @Nullable HttpStatus getStatusCode(); + /** + * Set the HTTP status code to the given value (potentially non-standard and + * not resolvable through the {@link HttpStatus} enum) as an integer. + * @param value the status code value + * @return {@code false} if the status code change wasn't processed because + * the HTTP response is committed, {@code true} if successfully set. + * @since 5.2.4 + */ + default boolean setRawStatusCode(@Nullable Integer value) { + if (value == null) { + return setStatusCode(null); + } + else { + HttpStatus httpStatus = HttpStatus.resolve(value); + if (httpStatus == null) { + throw new IllegalStateException( + "Unresolvable HttpStatus for general ServerHttpResponse: " + value); + } + return setStatusCode(httpStatus); + } + } + + /** + * Return the status code that has been set, or otherwise fall back on the + * status of the response from the underlying server. The return value may + * be {@code null} if there is no default value from the underlying server. + * @since 5.2.4 + */ + @Nullable + default Integer getRawStatusCode() { + HttpStatus httpStatus = getStatusCode(); + return (httpStatus != null ? httpStatus.value() : null); + } + /** * Return a mutable map with the cookies to send to the server. */ diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/ServletServerHttpResponse.java b/spring-web/src/main/java/org/springframework/http/server/reactive/ServletServerHttpResponse.java index b82233977e..ee52193b8d 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/ServletServerHttpResponse.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/ServletServerHttpResponse.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 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. @@ -100,15 +100,21 @@ class ServletServerHttpResponse extends AbstractListenerServerHttpResponse { @Override public HttpStatus getStatusCode() { - HttpStatus httpStatus = super.getStatusCode(); - return (httpStatus != null ? httpStatus : HttpStatus.resolve(this.response.getStatus())); + HttpStatus status = super.getStatusCode(); + return (status != null ? status : HttpStatus.resolve(this.response.getStatus())); + } + + @Override + public Integer getRawStatusCode() { + Integer status = super.getRawStatusCode(); + return (status != null ? status : this.response.getStatus()); } @Override protected void applyStatusCode() { - Integer statusCode = getStatusCodeValue(); - if (statusCode != null) { - this.response.setStatus(statusCode); + Integer status = super.getRawStatusCode(); + if (status != null) { + this.response.setStatus(status); } } diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/UndertowServerHttpResponse.java b/spring-web/src/main/java/org/springframework/http/server/reactive/UndertowServerHttpResponse.java index d19f839cb2..f20b4e6167 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/UndertowServerHttpResponse.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/UndertowServerHttpResponse.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 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. @@ -82,16 +82,21 @@ class UndertowServerHttpResponse extends AbstractListenerServerHttpResponse impl @Override public HttpStatus getStatusCode() { - HttpStatus httpStatus = super.getStatusCode(); - return (httpStatus != null ? httpStatus : HttpStatus.resolve(this.exchange.getStatusCode())); + HttpStatus status = super.getStatusCode(); + return (status != null ? status : HttpStatus.resolve(this.exchange.getStatusCode())); } + @Override + public Integer getRawStatusCode() { + Integer status = super.getRawStatusCode(); + return (status != null ? status : this.exchange.getStatusCode()); + } @Override protected void applyStatusCode() { - Integer statusCode = getStatusCodeValue(); - if (statusCode != null) { - this.exchange.setStatusCode(statusCode); + Integer status = super.getRawStatusCode(); + if (status != null) { + this.exchange.setStatusCode(status); } } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/DefaultServerResponseBuilder.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/DefaultServerResponseBuilder.java index a87b37a5c9..da71fbe565 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/DefaultServerResponseBuilder.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/DefaultServerResponseBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 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. @@ -45,7 +45,6 @@ import org.springframework.http.MediaType; import org.springframework.http.ReactiveHttpOutputMessage; import org.springframework.http.ResponseCookie; import org.springframework.http.codec.HttpMessageWriter; -import org.springframework.http.server.reactive.AbstractServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.util.Assert; @@ -354,17 +353,7 @@ class DefaultServerResponseBuilder implements ServerResponse.BodyBuilder { } private void writeStatusAndHeaders(ServerHttpResponse response) { - if (response instanceof AbstractServerHttpResponse) { - ((AbstractServerHttpResponse) response).setStatusCodeValue(this.statusCode); - } - else { - HttpStatus status = HttpStatus.resolve(this.statusCode); - if (status == null) { - throw new IllegalStateException( - "Unresolvable HttpStatus for general ServerHttpResponse: " + this.statusCode); - } - response.setStatusCode(status); - } + response.setRawStatusCode(this.statusCode); copy(this.headers, response.getHeaders()); copy(this.cookies, response.getCookies()); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandler.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandler.java index 2e642d706f..6c57bd1251 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandler.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 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. @@ -33,8 +33,6 @@ import org.springframework.http.HttpStatus; import org.springframework.http.RequestEntity; import org.springframework.http.ResponseEntity; import org.springframework.http.codec.HttpMessageWriter; -import org.springframework.http.server.reactive.AbstractServerHttpResponse; -import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.web.reactive.HandlerResult; @@ -141,14 +139,8 @@ public class ResponseEntityResultHandler extends AbstractMessageWriterResultHand } if (httpEntity instanceof ResponseEntity) { - ResponseEntity responseEntity = (ResponseEntity) httpEntity; - ServerHttpResponse response = exchange.getResponse(); - if (response instanceof AbstractServerHttpResponse) { - ((AbstractServerHttpResponse) response).setStatusCodeValue(responseEntity.getStatusCodeValue()); - } - else { - response.setStatusCode(responseEntity.getStatusCode()); - } + exchange.getResponse().setRawStatusCode( + ((ResponseEntity) httpEntity).getStatusCodeValue()); } HttpHeaders entityHeaders = httpEntity.getHeaders();