@@ -679,8 +679,8 @@ interface RequestHeadersSpec<S extends RequestHeadersSpec<S>> {
679
679
ResponseSpec retrieve ();
680
680
681
681
/**
682
- * Exchange the {@link ClientHttpResponse} for a type {@code T}. This
683
- * can be useful for advanced scenarios, for example to decode the
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
684
* response differently depending on the response status:
685
685
* <pre class="code">
686
686
* Person person = client.get()
@@ -700,15 +700,44 @@ interface RequestHeadersSpec<S extends RequestHeadersSpec<S>> {
700
700
* function has been invoked.
701
701
* @param exchangeFunction the function to handle the response with
702
702
* @param <T> the type the response will be transformed to
703
- * @return the value returned from the exchange function
703
+ * @return the value returned from the exchange function, potentially {@code null}
704
+ * @see RequestHeadersSpec#exchangeForRequiredValue(RequiredValueExchangeFunction)
704
705
*/
705
706
default <T > @ Nullable T exchange (ExchangeFunction <T > exchangeFunction ) {
706
707
return exchange (exchangeFunction , true );
707
708
}
708
709
709
710
/**
710
- * Exchange the {@link ClientHttpResponse} for a type {@code T}. This
711
- * can be useful for advanced scenarios, for example to decode the
711
+ * Exchange the {@link ClientHttpResponse} for a value of type {@code T}.
712
+ * This can be useful for advanced scenarios, for example to decode the
713
+ * response differently depending on the response status:
714
+ * <pre class="code">
715
+ * Person person = client.get()
716
+ * .uri("/people/1")
717
+ * .accept(MediaType.APPLICATION_JSON)
718
+ * .exchange((request, response) -> {
719
+ * if (response.getStatusCode().equals(HttpStatus.OK)) {
720
+ * return deserialize(response.getBody());
721
+ * }
722
+ * else {
723
+ * throw new BusinessException();
724
+ * }
725
+ * });
726
+ * </pre>
727
+ * <p><strong>Note:</strong> The response is
728
+ * {@linkplain ClientHttpResponse#close() closed} after the exchange
729
+ * function has been invoked.
730
+ * @param exchangeFunction the function to handle the response with
731
+ * @param <T> the type the response will be transformed to
732
+ * @return the value returned from the exchange function, never {@code null}
733
+ */
734
+ default <T > T exchangeForRequiredValue (RequiredValueExchangeFunction <T > exchangeFunction ) {
735
+ return exchangeForRequiredValue (exchangeFunction , true );
736
+ }
737
+
738
+ /**
739
+ * Exchange the {@link ClientHttpResponse} for a value of type {@code T}.
740
+ * This can be useful for advanced scenarios, for example to decode the
712
741
* response differently depending on the response status:
713
742
* <pre class="code">
714
743
* Person person = client.get()
@@ -731,10 +760,40 @@ interface RequestHeadersSpec<S extends RequestHeadersSpec<S>> {
731
760
* @param close {@code true} to close the response after
732
761
* {@code exchangeFunction} is invoked, {@code false} to keep it open
733
762
* @param <T> the type the response will be transformed to
734
- * @return the value returned from the exchange function
763
+ * @return the value returned from the exchange function, potentially {@code null}
764
+ * @see RequestHeadersSpec#exchangeForRequiredValue(RequiredValueExchangeFunction, boolean)
735
765
*/
736
766
<T > @ Nullable T exchange (ExchangeFunction <T > exchangeFunction , boolean close );
737
767
768
+ /**
769
+ * Exchange the {@link ClientHttpResponse} for a value of type {@code T}.
770
+ * This can be useful for advanced scenarios, for example to decode the
771
+ * response differently depending on the response status:
772
+ * <pre class="code">
773
+ * Person person = client.get()
774
+ * .uri("/people/1")
775
+ * .accept(MediaType.APPLICATION_JSON)
776
+ * .exchange((request, response) -> {
777
+ * if (response.getStatusCode().equals(HttpStatus.OK)) {
778
+ * return deserialize(response.getBody());
779
+ * }
780
+ * else {
781
+ * throw new BusinessException();
782
+ * }
783
+ * });
784
+ * </pre>
785
+ * <p><strong>Note:</strong> If {@code close} is {@code true},
786
+ * then the response is {@linkplain ClientHttpResponse#close() closed}
787
+ * after the exchange function has been invoked. When set to
788
+ * {@code false}, the caller is responsible for closing the response.
789
+ * @param exchangeFunction the function to handle the response with
790
+ * @param close {@code true} to close the response after
791
+ * {@code exchangeFunction} is invoked, {@code false} to keep it open
792
+ * @param <T> the type the response will be transformed to
793
+ * @return the value returned from the exchange function, never {@code null}
794
+ */
795
+ <T > T exchangeForRequiredValue (RequiredValueExchangeFunction <T > exchangeFunction , boolean close );
796
+
738
797
739
798
/**
740
799
* Defines the contract for {@link #exchange(ExchangeFunction)}.
@@ -744,15 +803,31 @@ interface RequestHeadersSpec<S extends RequestHeadersSpec<S>> {
744
803
interface ExchangeFunction <T > {
745
804
746
805
/**
747
- * Exchange the given response into a type {@code T}.
806
+ * Exchange the given response into a value of type {@code T}.
748
807
* @param clientRequest the request
749
808
* @param clientResponse the response
750
- * @return the exchanged type
809
+ * @return the exchanged value, potentially {@code null}
751
810
* @throws IOException in case of I/O errors
752
811
*/
753
812
@ Nullable T exchange (HttpRequest clientRequest , ConvertibleClientHttpResponse clientResponse ) throws IOException ;
754
813
}
755
814
815
+ /**
816
+ * Variant of {@link ExchangeFunction} returning a non-null required value.
817
+ * @param <T> the type the response will be transformed to
818
+ */
819
+ @ FunctionalInterface
820
+ interface RequiredValueExchangeFunction <T > extends ExchangeFunction <T > {
821
+
822
+ /**
823
+ * Exchange the given response into a value of type {@code T}.
824
+ * @param clientRequest the request
825
+ * @param clientResponse the response
826
+ * @return the exchanged value, never {@code null}
827
+ * @throws IOException in case of I/O errors
828
+ */
829
+ T exchange (HttpRequest clientRequest , ConvertibleClientHttpResponse clientResponse ) throws IOException ;
830
+ }
756
831
757
832
/**
758
833
* Extension of {@link ClientHttpResponse} that can convert the body.
0 commit comments