3939import org .springframework .util .ObjectUtils ;
4040
4141/**
42- * Used by {@link DefaultRestClient} and {@link DefaultRestClientBuilder}.
42+ * Simple container for an error response Predicate and an error response handler
43+ * to support the status handling mechanism of {@link RestClient.ResponseSpec}.
4344 *
4445 * @author Arjen Poutsma
46+ * @author Rossen Stoyanchev
4547 * @since 6.1
4648 */
4749final class StatusHandler {
4850
4951 private final ResponsePredicate predicate ;
5052
51- private final RestClient .ResponseSpec .ErrorHandler errorHandler ;
53+ private final RestClient .ResponseSpec .ErrorHandler handler ;
5254
5355
54- private StatusHandler (ResponsePredicate predicate , RestClient .ResponseSpec .ErrorHandler errorHandler ) {
56+ private StatusHandler (ResponsePredicate predicate , RestClient .ResponseSpec .ErrorHandler handler ) {
5557 this .predicate = predicate ;
56- this .errorHandler = errorHandler ;
58+ this .handler = handler ;
5759 }
5860
5961
60- public static StatusHandler of (Predicate <HttpStatusCode > predicate ,
61- RestClient .ResponseSpec .ErrorHandler errorHandler ) {
62+ /**
63+ * Test whether the response has any errors.
64+ */
65+ public boolean test (ClientHttpResponse response ) throws IOException {
66+ return this .predicate .test (response );
67+ }
68+
69+ /**
70+ * Handle the error in the given response.
71+ * <p>This method is only called when {@link #test(ClientHttpResponse)}
72+ * has returned {@code true}.
73+ ß */
74+ public void handle (HttpRequest request , ClientHttpResponse response ) throws IOException {
75+ this .handler .handle (request , response );
76+ }
77+
78+
79+ /**
80+ * Create a StatusHandler from a RestClient {@link RestClient.ResponseSpec.ErrorHandler}.
81+ */
82+ public static StatusHandler of (
83+ Predicate <HttpStatusCode > predicate , RestClient .ResponseSpec .ErrorHandler errorHandler ) {
84+
6285 Assert .notNull (predicate , "Predicate must not be null" );
6386 Assert .notNull (errorHandler , "ErrorHandler must not be null" );
6487
6588 return new StatusHandler (response -> predicate .test (response .getStatusCode ()), errorHandler );
6689 }
6790
91+ /**
92+ * Create a StatusHandler from a {@link ResponseErrorHandler}.
93+ */
6894 public static StatusHandler fromErrorHandler (ResponseErrorHandler errorHandler ) {
6995 Assert .notNull (errorHandler , "ResponseErrorHandler must not be null" );
7096
71- return new StatusHandler (errorHandler ::hasError , ( request , response ) ->
72- errorHandler .handleError (request .getURI (), request .getMethod (), response ));
97+ return new StatusHandler (errorHandler ::hasError ,
98+ ( request , response ) -> errorHandler .handleError (request .getURI (), request .getMethod (), response ));
7399 }
74100
75- public static StatusHandler defaultHandler (List <HttpMessageConverter <?>> messageConverters ) {
101+ /**
102+ * Create a StatusHandler for default error response handling.
103+ */
104+ public static StatusHandler createDefaultStatusHandler (List <HttpMessageConverter <?>> converters ) {
76105 return new StatusHandler (response -> response .getStatusCode ().isError (),
77106 (request , response ) -> {
78- HttpStatusCode statusCode = response .getStatusCode ();
79- String statusText = response .getStatusText ();
80- HttpHeaders headers = response .getHeaders ();
81- byte [] body = RestClientUtils .getBody (response );
82- Charset charset = RestClientUtils .getCharset (response );
83- String message = getErrorMessage (statusCode .value (), statusText , body , charset );
84- RestClientResponseException ex ;
85-
86- if (statusCode .is4xxClientError ()) {
87- ex = HttpClientErrorException .create (message , statusCode , statusText , headers , body , charset );
88- }
89- else if (statusCode .is5xxServerError ()) {
90- ex = HttpServerErrorException .create (message , statusCode , statusText , headers , body , charset );
91- }
92- else {
93- ex = new UnknownHttpStatusCodeException (message , statusCode .value (), statusText , headers , body , charset );
94- }
95- if (!CollectionUtils .isEmpty (messageConverters )) {
96- ex .setBodyConvertFunction (initBodyConvertFunction (response , body , messageConverters ));
97- }
98- throw ex ;
107+ throw createException (response , converters );
99108 });
100109 }
101110
102- @ SuppressWarnings ("NullAway" )
103- private static Function <ResolvableType , ? extends @ Nullable Object > initBodyConvertFunction (ClientHttpResponse response , byte [] body , List <HttpMessageConverter <?>> messageConverters ) {
104- Assert .state (!CollectionUtils .isEmpty (messageConverters ), "Expected message converters" );
105- return resolvableType -> {
106- try {
107- HttpMessageConverterExtractor <?> extractor =
108- new HttpMessageConverterExtractor <>(resolvableType .getType (), messageConverters );
111+ private static RestClientResponseException createException (
112+ ClientHttpResponse response , List <HttpMessageConverter <?>> converters ) throws IOException {
109113
110- return extractor .extractData (new ClientHttpResponseDecorator (response ) {
111- @ Override
112- public InputStream getBody () {
113- return new ByteArrayInputStream (body );
114- }
115- });
116- }
117- catch (IOException ex ) {
118- throw new RestClientException ("Error while extracting response for type [" + resolvableType + "]" , ex );
119- }
120- };
121- }
114+ HttpStatusCode statusCode = response .getStatusCode ();
115+ String statusText = response .getStatusText ();
116+ HttpHeaders headers = response .getHeaders ();
117+ byte [] body = RestClientUtils .getBody (response );
118+ Charset charset = RestClientUtils .getCharset (response );
119+ String message = getErrorMessage (statusCode .value (), statusText , body , charset );
120+ RestClientResponseException ex ;
122121
122+ if (statusCode .is4xxClientError ()) {
123+ ex = HttpClientErrorException .create (message , statusCode , statusText , headers , body , charset );
124+ }
125+ else if (statusCode .is5xxServerError ()) {
126+ ex = HttpServerErrorException .create (message , statusCode , statusText , headers , body , charset );
127+ }
128+ else {
129+ ex = new UnknownHttpStatusCodeException (message , statusCode .value (), statusText , headers , body , charset );
130+ }
131+ if (!CollectionUtils .isEmpty (converters )) {
132+ ex .setBodyConvertFunction (initBodyConvertFunction (response , body , converters ));
133+ }
134+ return ex ;
135+ }
123136
124- private static String getErrorMessage (int rawStatusCode , String statusText , byte @ Nullable [] responseBody ,
125- @ Nullable Charset charset ) {
137+ private static String getErrorMessage (
138+ int rawStatusCode , String statusText , byte @ Nullable [] responseBody , @ Nullable Charset charset ) {
126139
127140 String preface = rawStatusCode + " " + statusText + ": " ;
128141
@@ -138,14 +151,27 @@ private static String getErrorMessage(int rawStatusCode, String statusText, byte
138151 return preface + bodyText ;
139152 }
140153
154+ @ SuppressWarnings ("NullAway" )
155+ private static Function <ResolvableType , ? extends @ Nullable Object > initBodyConvertFunction (
156+ ClientHttpResponse response , byte [] body , List <HttpMessageConverter <?>> messageConverters ) {
141157
158+ Assert .state (!CollectionUtils .isEmpty (messageConverters ), "Expected message converters" );
159+ return resolvableType -> {
160+ try {
161+ HttpMessageConverterExtractor <?> extractor =
162+ new HttpMessageConverterExtractor <>(resolvableType .getType (), messageConverters );
142163
143- public boolean test (ClientHttpResponse response ) throws IOException {
144- return this .predicate .test (response );
145- }
146-
147- public void handle (HttpRequest request , ClientHttpResponse response ) throws IOException {
148- this .errorHandler .handle (request , response );
164+ return extractor .extractData (new ClientHttpResponseDecorator (response ) {
165+ @ Override
166+ public InputStream getBody () {
167+ return new ByteArrayInputStream (body );
168+ }
169+ });
170+ }
171+ catch (IOException ex ) {
172+ throw new RestClientException ("Error while extracting response for type [" + resolvableType + "]" , ex );
173+ }
174+ };
149175 }
150176
151177
0 commit comments