11/*
2- * Copyright 2002-2019 the original author or authors.
2+ * Copyright 2002-2020 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
2222import java .time .Instant ;
2323import java .time .ZonedDateTime ;
2424import java .util .Arrays ;
25+ import java .util .Map ;
2526import java .util .function .Consumer ;
27+ import java .util .function .Function ;
2628
2729import org .springframework .lang .Nullable ;
2830import org .springframework .util .MultiValueMap ;
2931import org .springframework .util .ObjectUtils ;
32+ import org .springframework .web .util .DefaultUriBuilderFactory ;
33+ import org .springframework .web .util .UriTemplateHandler ;
3034
3135/**
32- * Extension of {@link HttpEntity} that adds a {@linkplain HttpMethod method} and
33- * {@linkplain URI uri}. Used in {@code RestTemplate} and {@code @Controller} methods.
36+ * Extension of {@link HttpEntity} that also exposes the HTTP method and the
37+ * target URL. For use in the {@code RestTemplate} to prepare requests with
38+ * and in {@code @Controller} methods to represent request input.
3439 *
35- * <p>In {@code RestTemplate}, this class is used as parameter in
36- * {@link org.springframework.web.client.RestTemplate#exchange(RequestEntity, Class) exchange()}:
40+ * <p>Example use with the {@code RestTemplate}:
3741 * <pre class="code">
3842 * MyRequest body = ...
3943 * RequestEntity<MyRequest> request = RequestEntity
40- * .post(new URI( "https://example.com/bar") )
44+ * .post("https://example.com/{foo}", " bar")
4145 * .accept(MediaType.APPLICATION_JSON)
4246 * .body(body);
4347 * ResponseEntity<MyResponse> response = template.exchange(request, MyResponse.class);
4448 * </pre>
4549 *
46- * <p>If you would like to provide a URI template with variables, consider using
47- * {@link org.springframework.web.util.DefaultUriBuilderFactory DefaultUriBuilderFactory}:
48- * <pre class="code">
49- * // Create shared factory
50- * UriBuilderFactory factory = new DefaultUriBuilderFactory();
51- *
52- * // Use factory to create URL from template
53- * URI uri = factory.uriString("https://example.com/{foo}").build("bar");
54- * RequestEntity<MyRequest> request = RequestEntity.post(uri).accept(MediaType.APPLICATION_JSON).body(body);
55- * </pre>
56- *
57- * <p>Can also be used in Spring MVC, as a parameter in a @Controller method:
50+ * <p>Example use in an {@code @Controller}:
5851 * <pre class="code">
5952 * @RequestMapping("/handle")
6053 * public void handle(RequestEntity<String> request) {
6659 *
6760 * @author Arjen Poutsma
6861 * @author Sebastien Deleuze
62+ * @author Parviz Rozikov
6963 * @since 4.1
7064 * @param <T> the body type
7165 * @see #getMethod()
7266 * @see #getUrl()
7367 */
7468public class RequestEntity <T > extends HttpEntity <T > {
7569
70+ private final static UriTemplateHandler DEFAULT_TEMPLATE_HANDLER = new DefaultUriBuilderFactory ();
71+
7672 @ Nullable
7773 private final HttpMethod method ;
7874
79- private final URI url ;
75+ private final Function < UriTemplateHandler , URI > uriFunction ;
8076
8177 @ Nullable
8278 private final Type type ;
@@ -148,9 +144,19 @@ public RequestEntity(@Nullable T body, @Nullable MultiValueMap<String, String> h
148144 public RequestEntity (@ Nullable T body , @ Nullable MultiValueMap <String , String > headers ,
149145 @ Nullable HttpMethod method , URI url , @ Nullable Type type ) {
150146
147+ this (body , headers , method , handler -> url , type );
148+ }
149+
150+ /**
151+ * Private constructor with URI function.
152+ * @since 5.3
153+ */
154+ private RequestEntity (@ Nullable T body , @ Nullable MultiValueMap <String , String > headers ,
155+ @ Nullable HttpMethod method , Function <UriTemplateHandler , URI > uriFunction , @ Nullable Type type ) {
156+
151157 super (body , headers );
152158 this .method = method ;
153- this .url = url ;
159+ this .uriFunction = uriFunction ;
154160 this .type = type ;
155161 }
156162
@@ -166,12 +172,27 @@ public HttpMethod getMethod() {
166172
167173 /**
168174 * Return the URL of the request.
175+ * <p>If the URL was provided as a URI template, the returned URI is expanded
176+ * and encoded with {@link DefaultUriBuilderFactory}.
169177 * @return the URL as a {@code URI}
170178 */
171179 public URI getUrl () {
172- return this .url ;
180+ return this .uriFunction . apply ( DEFAULT_TEMPLATE_HANDLER ) ;
173181 }
174182
183+ /**
184+ * Return the URL of the request.
185+ * <p>If the URL was provided as a URI template, the returned URI is expanded
186+ * with the given {@link DefaultUriBuilderFactory}.
187+ * @param templateHandler the handler to use to expand the URI template with
188+ * @return the URL as a {@code URI}
189+ * @since 5.3
190+ */
191+ public URI getUrl (UriTemplateHandler templateHandler ) {
192+ return this .uriFunction .apply (templateHandler );
193+ }
194+
195+
175196 /**
176197 * Return the type of the request's body.
177198 * @return the request's body type, or {@code null} if not known
@@ -206,7 +227,7 @@ public boolean equals(@Nullable Object other) {
206227 public int hashCode () {
207228 int hashCode = super .hashCode ();
208229 hashCode = 29 * hashCode + ObjectUtils .nullSafeHashCode (this .method );
209- hashCode = 29 * hashCode + ObjectUtils .nullSafeHashCode (this . url );
230+ hashCode = 29 * hashCode + ObjectUtils .nullSafeHashCode (getUrl () );
210231 return hashCode ;
211232 }
212233
@@ -241,6 +262,30 @@ public static BodyBuilder method(HttpMethod method, URI url) {
241262 return new DefaultBodyBuilder (method , url );
242263 }
243264
265+ /**
266+ * Create a builder with the given HTTP method, URI template, and variables.
267+ * @param method the HTTP method (GET, POST, etc)
268+ * @param uriTemplate the uri template to use
269+ * @param uriVariables variables to expand the URI template with
270+ * @return the created builder
271+ * @since 5.3
272+ */
273+ public static BodyBuilder method (HttpMethod method , String uriTemplate , Object ... uriVariables ) {
274+ return new DefaultBodyBuilder (method , uriTemplate , uriVariables );
275+ }
276+
277+ /**
278+ * Create a builder with the given HTTP method, URI template, and variables.
279+ * @param method the HTTP method (GET, POST, etc)
280+ * @param uriTemplate the uri template to use
281+ * @return the created builder
282+ * @since 5.3
283+ */
284+ public static BodyBuilder method (HttpMethod method , String uriTemplate , Map <String , ?> uriVariables ) {
285+ return new DefaultBodyBuilder (method , uriTemplate , uriVariables );
286+ }
287+
288+
244289 /**
245290 * Create an HTTP GET builder with the given url.
246291 * @param url the URL
@@ -250,6 +295,17 @@ public static HeadersBuilder<?> get(URI url) {
250295 return method (HttpMethod .GET , url );
251296 }
252297
298+ /**
299+ * Create an HTTP GET builder with the given string base uri template.
300+ * @param uriTemplate the uri template to use
301+ * @param uriVariables variables to expand the URI template with
302+ * @return the created builder
303+ * @since 5.3
304+ */
305+ public static HeadersBuilder <?> get (String uriTemplate , Object ... uriVariables ) {
306+ return method (HttpMethod .GET , uriTemplate , uriVariables );
307+ }
308+
253309 /**
254310 * Create an HTTP HEAD builder with the given url.
255311 * @param url the URL
@@ -259,6 +315,17 @@ public static HeadersBuilder<?> head(URI url) {
259315 return method (HttpMethod .HEAD , url );
260316 }
261317
318+ /**
319+ * Create an HTTP HEAD builder with the given string base uri template.
320+ * @param uriTemplate the uri template to use
321+ * @param uriVariables variables to expand the URI template with
322+ * @return the created builder
323+ * @since 5.3
324+ */
325+ public static HeadersBuilder <?> head (String uriTemplate , Object ... uriVariables ) {
326+ return method (HttpMethod .HEAD , uriTemplate , uriVariables );
327+ }
328+
262329 /**
263330 * Create an HTTP POST builder with the given url.
264331 * @param url the URL
@@ -268,6 +335,17 @@ public static BodyBuilder post(URI url) {
268335 return method (HttpMethod .POST , url );
269336 }
270337
338+ /**
339+ * Create an HTTP POST builder with the given string base uri template.
340+ * @param uriTemplate the uri template to use
341+ * @param uriVariables variables to expand the URI template with
342+ * @return the created builder
343+ * @since 5.3
344+ */
345+ public static BodyBuilder post (String uriTemplate , Object ... uriVariables ) {
346+ return method (HttpMethod .POST , uriTemplate , uriVariables );
347+ }
348+
271349 /**
272350 * Create an HTTP PUT builder with the given url.
273351 * @param url the URL
@@ -277,6 +355,17 @@ public static BodyBuilder put(URI url) {
277355 return method (HttpMethod .PUT , url );
278356 }
279357
358+ /**
359+ * Create an HTTP PUT builder with the given string base uri template.
360+ * @param uriTemplate the uri template to use
361+ * @param uriVariables variables to expand the URI template with
362+ * @return the created builder
363+ * @since 5.3
364+ */
365+ public static BodyBuilder put (String uriTemplate , Object ... uriVariables ) {
366+ return method (HttpMethod .PUT , uriTemplate , uriVariables );
367+ }
368+
280369 /**
281370 * Create an HTTP PATCH builder with the given url.
282371 * @param url the URL
@@ -286,6 +375,17 @@ public static BodyBuilder patch(URI url) {
286375 return method (HttpMethod .PATCH , url );
287376 }
288377
378+ /**
379+ * Create an HTTP PATCH builder with the given string base uri template.
380+ * @param uriTemplate the uri template to use
381+ * @param uriVariables variables to expand the URI template with
382+ * @return the created builder
383+ * @since 5.3
384+ */
385+ public static BodyBuilder patch (String uriTemplate , Object ... uriVariables ) {
386+ return method (HttpMethod .PATCH , uriTemplate , uriVariables );
387+ }
388+
289389 /**
290390 * Create an HTTP DELETE builder with the given url.
291391 * @param url the URL
@@ -295,6 +395,17 @@ public static HeadersBuilder<?> delete(URI url) {
295395 return method (HttpMethod .DELETE , url );
296396 }
297397
398+ /**
399+ * Create an HTTP DELETE builder with the given string base uri template.
400+ * @param uriTemplate the uri template to use
401+ * @param uriVariables variables to expand the URI template with
402+ * @return the created builder
403+ * @since 5.3
404+ */
405+ public static HeadersBuilder <?> delete (String uriTemplate , Object ... uriVariables ) {
406+ return method (HttpMethod .DELETE , uriTemplate , uriVariables );
407+ }
408+
298409 /**
299410 * Creates an HTTP OPTIONS builder with the given url.
300411 * @param url the URL
@@ -304,6 +415,17 @@ public static HeadersBuilder<?> options(URI url) {
304415 return method (HttpMethod .OPTIONS , url );
305416 }
306417
418+ /**
419+ * Creates an HTTP OPTIONS builder with the given string base uri template.
420+ * @param uriTemplate the uri template to use
421+ * @param uriVariables variables to expand the URI template with
422+ * @return the created builder
423+ * @since 5.3
424+ */
425+ public static HeadersBuilder <?> options (String uriTemplate , Object ... uriVariables ) {
426+ return method (HttpMethod .OPTIONS , uriTemplate , uriVariables );
427+ }
428+
307429
308430 /**
309431 * Defines a builder that adds headers to the request entity.
@@ -439,13 +561,24 @@ private static class DefaultBodyBuilder implements BodyBuilder {
439561
440562 private final HttpMethod method ;
441563
442- private final URI url ;
564+ private final Function < UriTemplateHandler , URI > uriFunction ;
443565
444566 private final HttpHeaders headers = new HttpHeaders ();
445567
568+
446569 public DefaultBodyBuilder (HttpMethod method , URI url ) {
447570 this .method = method ;
448- this .url = url ;
571+ this .uriFunction = handler -> url ;
572+ }
573+
574+ public DefaultBodyBuilder (HttpMethod method , String uriTemplate , Object ... uriVars ) {
575+ this .method = method ;
576+ this .uriFunction = handler -> handler .expand (uriTemplate , uriVars );
577+ }
578+
579+ public DefaultBodyBuilder (HttpMethod method , String uriTemplate , Map <String , ?> uriVars ) {
580+ this .method = method ;
581+ this .uriFunction = handler -> handler .expand (uriTemplate , uriVars );
449582 }
450583
451584 @ Override
@@ -520,18 +653,17 @@ public BodyBuilder ifNoneMatch(String... ifNoneMatches) {
520653
521654 @ Override
522655 public RequestEntity <Void > build () {
523- return new RequestEntity <>(this .headers , this .method , this .url );
656+ return new RequestEntity <>(null , this .headers , this .method , this .uriFunction , null );
524657 }
525658
526659 @ Override
527660 public <T > RequestEntity <T > body (T body ) {
528- return new RequestEntity <>(body , this .headers , this .method , this .url );
661+ return new RequestEntity <>(body , this .headers , this .method , this .uriFunction , null );
529662 }
530663
531664 @ Override
532665 public <T > RequestEntity <T > body (T body , Type type ) {
533- return new RequestEntity <>(body , this .headers , this .method , this .url , type );
666+ return new RequestEntity <>(body , this .headers , this .method , this .uriFunction , type );
534667 }
535668 }
536-
537669}
0 commit comments