@@ -671,12 +671,41 @@ interface RequestHeadersSpec<S extends RequestHeadersSpec<S>> {
671
671
* @param exchangeFunction the function to handle the response with
672
672
* @param <T> the type the response will be transformed to
673
673
* @return the value returned from the exchange function, potentially {@code null}
674
+ * @see RequestHeadersSpec#exchangeForRequiredValue(RequiredValueExchangeFunction)
674
675
*/
675
676
@ Nullable
676
677
default <T > T exchange (ExchangeFunction <T > exchangeFunction ) {
677
678
return exchange (exchangeFunction , true );
678
679
}
679
680
681
+ /**
682
+ * Exchange the {@link ClientHttpResponse} for a value of type {@code T}.
683
+ * This can be useful for advanced scenarios, for example to decode the
684
+ * response differently depending on the response status:
685
+ * <pre class="code">
686
+ * Person person = client.get()
687
+ * .uri("/people/1")
688
+ * .accept(MediaType.APPLICATION_JSON)
689
+ * .exchange((request, response) -> {
690
+ * if (response.getStatusCode().equals(HttpStatus.OK)) {
691
+ * return deserialize(response.getBody());
692
+ * }
693
+ * else {
694
+ * throw new BusinessException();
695
+ * }
696
+ * });
697
+ * </pre>
698
+ * <p><strong>Note:</strong> The response is
699
+ * {@linkplain ClientHttpResponse#close() closed} after the exchange
700
+ * function has been invoked.
701
+ * @param exchangeFunction the function to handle the response with
702
+ * @param <T> the type the response will be transformed to
703
+ * @return the value returned from the exchange function, never {@code null}
704
+ */
705
+ default <T > T exchangeForRequiredValue (RequiredValueExchangeFunction <T > exchangeFunction ) {
706
+ return exchangeForRequiredValue (exchangeFunction , true );
707
+ }
708
+
680
709
/**
681
710
* Exchange the {@link ClientHttpResponse} for a value of type {@code T}.
682
711
* This can be useful for advanced scenarios, for example to decode the
@@ -703,10 +732,40 @@ default <T> T exchange(ExchangeFunction<T> exchangeFunction) {
703
732
* {@code exchangeFunction} is invoked, {@code false} to keep it open
704
733
* @param <T> the type the response will be transformed to
705
734
* @return the value returned from the exchange function, potentially {@code null}
735
+ * @see RequestHeadersSpec#exchangeForRequiredValue(RequiredValueExchangeFunction, boolean)
706
736
*/
707
737
@ Nullable
708
738
<T > T exchange (ExchangeFunction <T > exchangeFunction , boolean close );
709
739
740
+ /**
741
+ * Exchange the {@link ClientHttpResponse} for a value of type {@code T}.
742
+ * This can be useful for advanced scenarios, for example to decode the
743
+ * response differently depending on the response status:
744
+ * <pre class="code">
745
+ * Person person = client.get()
746
+ * .uri("/people/1")
747
+ * .accept(MediaType.APPLICATION_JSON)
748
+ * .exchange((request, response) -> {
749
+ * if (response.getStatusCode().equals(HttpStatus.OK)) {
750
+ * return deserialize(response.getBody());
751
+ * }
752
+ * else {
753
+ * throw new BusinessException();
754
+ * }
755
+ * });
756
+ * </pre>
757
+ * <p><strong>Note:</strong> If {@code close} is {@code true},
758
+ * then the response is {@linkplain ClientHttpResponse#close() closed}
759
+ * after the exchange function has been invoked. When set to
760
+ * {@code false}, the caller is responsible for closing the response.
761
+ * @param exchangeFunction the function to handle the response with
762
+ * @param close {@code true} to close the response after
763
+ * {@code exchangeFunction} is invoked, {@code false} to keep it open
764
+ * @param <T> the type the response will be transformed to
765
+ * @return the value returned from the exchange function, never {@code null}
766
+ */
767
+ <T > T exchangeForRequiredValue (RequiredValueExchangeFunction <T > exchangeFunction , boolean close );
768
+
710
769
711
770
/**
712
771
* Defines the contract for {@link #exchange(ExchangeFunction)}.
@@ -726,6 +785,22 @@ interface ExchangeFunction<T> {
726
785
T exchange (HttpRequest clientRequest , ConvertibleClientHttpResponse clientResponse ) throws IOException ;
727
786
}
728
787
788
+ /**
789
+ * Variant of {@link ExchangeFunction} returning a non-null required value.
790
+ * @param <T> the type the response will be transformed to
791
+ */
792
+ @ FunctionalInterface
793
+ interface RequiredValueExchangeFunction <T > extends ExchangeFunction <T > {
794
+
795
+ /**
796
+ * Exchange the given response into a value of type {@code T}.
797
+ * @param clientRequest the request
798
+ * @param clientResponse the response
799
+ * @return the exchanged value, never {@code null}
800
+ * @throws IOException in case of I/O errors
801
+ */
802
+ T exchange (HttpRequest clientRequest , ConvertibleClientHttpResponse clientResponse ) throws IOException ;
803
+ }
729
804
730
805
/**
731
806
* Extension of {@link ClientHttpResponse} that can convert the body.
0 commit comments