001/* 002 * Copyright 2002-2019 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.reactive.function.server; 018 019import java.net.URI; 020import java.time.Instant; 021import java.time.ZonedDateTime; 022import java.util.Map; 023import java.util.Set; 024import java.util.function.Consumer; 025 026import org.reactivestreams.Publisher; 027import reactor.core.publisher.Mono; 028 029import org.springframework.core.ParameterizedTypeReference; 030import org.springframework.http.CacheControl; 031import org.springframework.http.HttpHeaders; 032import org.springframework.http.HttpMethod; 033import org.springframework.http.HttpStatus; 034import org.springframework.http.MediaType; 035import org.springframework.http.ResponseCookie; 036import org.springframework.http.codec.json.Jackson2CodecSupport; 037import org.springframework.http.server.reactive.ServerHttpResponse; 038import org.springframework.util.MultiValueMap; 039import org.springframework.web.reactive.function.BodyInserter; 040import org.springframework.web.reactive.function.BodyInserters; 041 042/** 043 * Entity-specific subtype of {@link ServerResponse} that exposes entity data. 044 * 045 * @author Arjen Poutsma 046 * @author Juergen Hoeller 047 * @since 5.0 048 * @param <T> the entity type 049 */ 050public interface EntityResponse<T> extends ServerResponse { 051 052 /** 053 * Return the entity that makes up this response. 054 */ 055 T entity(); 056 057 /** 058 * Return the {@code BodyInserter} that writes the entity to the output stream. 059 */ 060 BodyInserter<T, ? super ServerHttpResponse> inserter(); 061 062 063 // Static builder methods 064 065 /** 066 * Create a builder with the given object. 067 * @param body the object that represents the body of the response 068 * @param <T> the type of the body 069 * @return the created builder 070 */ 071 static <T> Builder<T> fromObject(T body) { 072 return new DefaultEntityResponseBuilder<>(body, BodyInserters.fromValue(body)); 073 } 074 075 /** 076 * Create a builder with the given producer. 077 * @param producer the producer that represents the body of the response 078 * @param elementClass the class of elements contained in the publisher 079 * @return the created builder 080 * @since 5.2 081 */ 082 static <T> Builder<T> fromProducer(T producer, Class<?> elementClass) { 083 return new DefaultEntityResponseBuilder<>(producer, 084 BodyInserters.fromProducer(producer, elementClass)); 085 } 086 087 /** 088 * Create a builder with the given producer. 089 * @param producer the producer that represents the body of the response 090 * @param typeReference the type of elements contained in the producer 091 * @return the created builder 092 * @since 5.2 093 */ 094 static <T> Builder<T> fromProducer(T producer, ParameterizedTypeReference<?> typeReference) { 095 return new DefaultEntityResponseBuilder<>(producer, 096 BodyInserters.fromProducer(producer, typeReference)); 097 } 098 099 /** 100 * Create a builder with the given publisher. 101 * @param publisher the publisher that represents the body of the response 102 * @param elementClass the class of elements contained in the publisher 103 * @param <T> the type of the elements contained in the publisher 104 * @param <P> the type of the {@code Publisher} 105 * @return the created builder 106 */ 107 static <T, P extends Publisher<T>> Builder<P> fromPublisher(P publisher, Class<T> elementClass) { 108 return new DefaultEntityResponseBuilder<>(publisher, 109 BodyInserters.fromPublisher(publisher, elementClass)); 110 } 111 112 /** 113 * Create a builder with the given publisher. 114 * @param publisher the publisher that represents the body of the response 115 * @param typeReference the type of elements contained in the publisher 116 * @param <T> the type of the elements contained in the publisher 117 * @param <P> the type of the {@code Publisher} 118 * @return the created builder 119 */ 120 static <T, P extends Publisher<T>> Builder<P> fromPublisher(P publisher, 121 ParameterizedTypeReference<T> typeReference) { 122 123 return new DefaultEntityResponseBuilder<>(publisher, 124 BodyInserters.fromPublisher(publisher, typeReference)); 125 } 126 127 128 /** 129 * Defines a builder for {@code EntityResponse}. 130 * 131 * @param <T> a self reference to the builder type 132 */ 133 interface Builder<T> { 134 135 /** 136 * Add the given header value(s) under the given name. 137 * @param headerName the header name 138 * @param headerValues the header value(s) 139 * @return this builder 140 * @see HttpHeaders#add(String, String) 141 */ 142 Builder<T> header(String headerName, String... headerValues); 143 144 /** 145 * Copy the given headers into the entity's headers map. 146 * @param headers the existing HttpHeaders to copy from 147 * @return this builder 148 * @see HttpHeaders#add(String, String) 149 */ 150 Builder<T> headers(HttpHeaders headers); 151 152 /** 153 * Set the HTTP status. 154 * @param status the response status 155 * @return this builder 156 */ 157 Builder<T> status(HttpStatus status); 158 159 /** 160 * Set the HTTP status. 161 * @param status the response status 162 * @return this builder 163 * @since 5.0.3 164 */ 165 Builder<T> status(int status); 166 167 /** 168 * Add the given cookie to the response. 169 * @param cookie the cookie to add 170 * @return this builder 171 */ 172 Builder<T> cookie(ResponseCookie cookie); 173 174 /** 175 * Manipulate this response's cookies with the given consumer. The 176 * cookies provided to the consumer are "live", so that the consumer can be used to 177 * {@linkplain MultiValueMap#set(Object, Object) overwrite} existing cookies, 178 * {@linkplain MultiValueMap#remove(Object) remove} cookies, or use any of the other 179 * {@link MultiValueMap} methods. 180 * @param cookiesConsumer a function that consumes the cookies 181 * @return this builder 182 */ 183 Builder<T> cookies(Consumer<MultiValueMap<String, ResponseCookie>> cookiesConsumer); 184 185 /** 186 * Set the set of allowed {@link HttpMethod HTTP methods}, as specified 187 * by the {@code Allow} header. 188 * @param allowedMethods the allowed methods 189 * @return this builder 190 * @see HttpHeaders#setAllow(Set) 191 */ 192 Builder<T> allow(HttpMethod... allowedMethods); 193 194 /** 195 * Set the set of allowed {@link HttpMethod HTTP methods}, as specified 196 * by the {@code Allow} header. 197 * @param allowedMethods the allowed methods 198 * @return this builder 199 * @see HttpHeaders#setAllow(Set) 200 */ 201 Builder<T> allow(Set<HttpMethod> allowedMethods); 202 203 /** 204 * Set the entity tag of the body, as specified by the {@code ETag} header. 205 * @param etag the new entity tag 206 * @return this builder 207 * @see HttpHeaders#setETag(String) 208 */ 209 Builder<T> eTag(String etag); 210 211 /** 212 * Set the time the resource was last changed, as specified by the 213 * {@code Last-Modified} header. 214 * <p>The date should be specified as the number of milliseconds since 215 * January 1, 1970 GMT. 216 * @param lastModified the last modified date 217 * @return this builder 218 * @see HttpHeaders#setLastModified(long) 219 */ 220 Builder<T> lastModified(ZonedDateTime lastModified); 221 222 /** 223 * Set the time the resource was last changed, as specified by the 224 * {@code Last-Modified} header. 225 * <p>The date should be specified as the number of milliseconds since 226 * January 1, 1970 GMT. 227 * @param lastModified the last modified date 228 * @return this builder 229 * @since 5.1.4 230 * @see HttpHeaders#setLastModified(long) 231 */ 232 Builder<T> lastModified(Instant lastModified); 233 234 /** 235 * Set the location of a resource, as specified by the {@code Location} header. 236 * @param location the location 237 * @return this builder 238 * @see HttpHeaders#setLocation(URI) 239 */ 240 Builder<T> location(URI location); 241 242 /** 243 * Set the caching directives for the resource, as specified by the HTTP 1.1 244 * {@code Cache-Control} header. 245 * <p>A {@code CacheControl} instance can be built like 246 * {@code CacheControl.maxAge(3600).cachePublic().noTransform()}. 247 * @param cacheControl a builder for cache-related HTTP response headers 248 * @return this builder 249 * @see <a href="https://tools.ietf.org/html/rfc7234#section-5.2">RFC-7234 Section 5.2</a> 250 */ 251 Builder<T> cacheControl(CacheControl cacheControl); 252 253 /** 254 * Configure one or more request header names (e.g. "Accept-Language") to 255 * add to the "Vary" response header to inform clients that the response is 256 * subject to content negotiation and variances based on the value of the 257 * given request headers. The configured request header names are added only 258 * if not already present in the response "Vary" header. 259 * @param requestHeaders request header names 260 * @return this builder 261 */ 262 Builder<T> varyBy(String... requestHeaders); 263 264 /** 265 * Set the length of the body in bytes, as specified by the 266 * {@code Content-Length} header. 267 * @param contentLength the content length 268 * @return this builder 269 * @see HttpHeaders#setContentLength(long) 270 */ 271 Builder<T> contentLength(long contentLength); 272 273 /** 274 * Set the {@linkplain MediaType media type} of the body, as specified by the 275 * {@code Content-Type} header. 276 * @param contentType the content type 277 * @return this builder 278 * @see HttpHeaders#setContentType(MediaType) 279 */ 280 Builder<T> contentType(MediaType contentType); 281 282 /** 283 * Add a serialization hint like {@link Jackson2CodecSupport#JSON_VIEW_HINT} to 284 * customize how the body will be serialized. 285 * @param key the hint key 286 * @param value the hint value 287 */ 288 Builder<T> hint(String key, Object value); 289 290 /** 291 * Customize the serialization hints with the given consumer. 292 * @param hintsConsumer a function that consumes the hints 293 * @return this builder 294 * @since 5.1.6 295 */ 296 Builder<T> hints(Consumer<Map<String, Object>> hintsConsumer); 297 298 /** 299 * Build the response. 300 * @return the built response 301 */ 302 Mono<EntityResponse<T>> build(); 303 } 304 305}