github.com/phrase/openapi@v0.0.0-20240514140800-49e8a106740e/openapi-generator/templates/java/libraries/resttemplate/ApiClient.mustache (about) 1 package {{invokerPackage}}; 2 3 {{#withXml}} 4 import com.fasterxml.jackson.dataformat.xml.XmlMapper; 5 import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator; 6 {{/withXml}} 7 import org.apache.commons.logging.Log; 8 import org.apache.commons.logging.LogFactory; 9 import org.springframework.beans.factory.annotation.Autowired; 10 import org.springframework.core.ParameterizedTypeReference; 11 import org.springframework.http.HttpHeaders; 12 import org.springframework.http.HttpMethod; 13 import org.springframework.http.HttpRequest; 14 import org.springframework.http.HttpStatus; 15 import org.springframework.http.InvalidMediaTypeException; 16 import org.springframework.http.MediaType; 17 import org.springframework.http.RequestEntity; 18 import org.springframework.http.RequestEntity.BodyBuilder; 19 import org.springframework.http.ResponseEntity; 20 import org.springframework.http.client.BufferingClientHttpRequestFactory; 21 import org.springframework.http.client.ClientHttpRequestExecution; 22 import org.springframework.http.client.ClientHttpRequestInterceptor; 23 import org.springframework.http.client.ClientHttpResponse; 24 {{#withXml}} 25 import org.springframework.http.converter.HttpMessageConverter; 26 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; 27 import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter; 28 {{/withXml}} 29 import org.springframework.stereotype.Component; 30 import org.springframework.util.LinkedMultiValueMap; 31 import org.springframework.util.MultiValueMap; 32 import org.springframework.util.StringUtils; 33 import org.springframework.web.client.RestClientException; 34 import org.springframework.web.client.RestTemplate; 35 import org.springframework.web.util.UriComponentsBuilder; 36 {{#threetenbp}} 37 import org.threeten.bp.*; 38 import com.fasterxml.jackson.datatype.threetenbp.ThreeTenModule; 39 import org.springframework.http.converter.HttpMessageConverter; 40 import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter; 41 import com.fasterxml.jackson.databind.ObjectMapper; 42 import org.openapitools.jackson.nullable.JsonNullableModule; 43 {{/threetenbp}} 44 45 import java.io.BufferedReader; 46 import java.io.IOException; 47 import java.io.InputStream; 48 import java.io.InputStreamReader; 49 import java.io.UnsupportedEncodingException; 50 import java.net.URI; 51 import java.net.URISyntaxException; 52 import java.net.URLEncoder; 53 import java.nio.charset.StandardCharsets; 54 import java.text.DateFormat; 55 import java.text.ParseException; 56 import java.util.Arrays; 57 import java.util.ArrayList; 58 import java.util.Collection; 59 import java.util.Collections; 60 import java.util.Date; 61 import java.util.HashMap; 62 import java.util.Iterator; 63 import java.util.List; 64 import java.util.Map; 65 import java.util.Map.Entry; 66 import java.util.TimeZone; 67 68 import {{invokerPackage}}.auth.Authentication; 69 import {{invokerPackage}}.auth.HttpBasicAuth; 70 import {{invokerPackage}}.auth.HttpBearerAuth; 71 import {{invokerPackage}}.auth.ApiKeyAuth; 72 {{#hasOAuthMethods}} 73 import {{invokerPackage}}.auth.OAuth; 74 {{/hasOAuthMethods}} 75 76 {{>generatedAnnotation}} 77 @Component("{{invokerPackage}}.ApiClient") 78 public class ApiClient { 79 public enum CollectionFormat { 80 CSV(","), TSV("\t"), SSV(" "), PIPES("|"), MULTI(null); 81 82 private final String separator; 83 private CollectionFormat(String separator) { 84 this.separator = separator; 85 } 86 87 private String collectionToString(Collection<?> collection) { 88 return StringUtils.collectionToDelimitedString(collection, separator); 89 } 90 } 91 92 private boolean debugging = false; 93 94 private HttpHeaders defaultHeaders = new HttpHeaders(); 95 private MultiValueMap<String, String> defaultCookies = new LinkedMultiValueMap<String, String>(); 96 97 private String basePath = "{{basePath}}"; 98 99 private RestTemplate restTemplate; 100 101 private Map<String, Authentication> authentications; 102 103 private DateFormat dateFormat; 104 105 public ApiClient() { 106 this.restTemplate = buildRestTemplate(); 107 init(); 108 } 109 110 @Autowired 111 public ApiClient(RestTemplate restTemplate) { 112 this.restTemplate = restTemplate; 113 init(); 114 } 115 116 protected void init() { 117 // Use RFC3339 format for date and datetime. 118 // See http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14 119 this.dateFormat = new RFC3339DateFormat(); 120 121 // Use UTC as the default time zone. 122 this.dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); 123 124 // Set default User-Agent. 125 setUserAgent("Java-SDK"); 126 127 // Setup authentications (key: authentication name, value: authentication). 128 authentications = new HashMap<String, Authentication>();{{#authMethods}}{{#isBasic}}{{#isBasicBasic}} 129 authentications.put("{{name}}", new HttpBasicAuth());{{/isBasicBasic}}{{^isBasicBasic}} 130 authentications.put("{{name}}", new HttpBearerAuth("{{scheme}}"));{{/isBasicBasic}}{{/isBasic}}{{#isApiKey}} 131 authentications.put("{{name}}", new ApiKeyAuth({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{^isKeyInHeader}}"query"{{/isKeyInHeader}}, "{{keyParamName}}"));{{/isApiKey}}{{#isOAuth}} 132 authentications.put("{{name}}", new OAuth());{{/isOAuth}}{{/authMethods}} 133 // Prevent the authentications from being modified. 134 authentications = Collections.unmodifiableMap(authentications); 135 } 136 137 /** 138 * Get the current base path 139 * @return String the base path 140 */ 141 public String getBasePath() { 142 return basePath; 143 } 144 145 /** 146 * Set the base path, which should include the host 147 * @param basePath the base path 148 * @return ApiClient this client 149 */ 150 public ApiClient setBasePath(String basePath) { 151 this.basePath = basePath; 152 return this; 153 } 154 155 /** 156 * Get authentications (key: authentication name, value: authentication). 157 * @return Map the currently configured authentication types 158 */ 159 public Map<String, Authentication> getAuthentications() { 160 return authentications; 161 } 162 163 /** 164 * Get authentication for the given name. 165 * 166 * @param authName The authentication name 167 * @return The authentication, null if not found 168 */ 169 public Authentication getAuthentication(String authName) { 170 return authentications.get(authName); 171 } 172 173 /** 174 * Helper method to set token for HTTP bearer authentication. 175 * @param bearerToken the token 176 */ 177 public void setBearerToken(String bearerToken) { 178 for (Authentication auth : authentications.values()) { 179 if (auth instanceof HttpBearerAuth) { 180 ((HttpBearerAuth) auth).setBearerToken(bearerToken); 181 return; 182 } 183 } 184 throw new RuntimeException("No Bearer authentication configured!"); 185 } 186 187 /** 188 * Helper method to set username for the first HTTP basic authentication. 189 * @param username the username 190 */ 191 public void setUsername(String username) { 192 for (Authentication auth : authentications.values()) { 193 if (auth instanceof HttpBasicAuth) { 194 ((HttpBasicAuth) auth).setUsername(username); 195 return; 196 } 197 } 198 throw new RuntimeException("No HTTP basic authentication configured!"); 199 } 200 201 /** 202 * Helper method to set password for the first HTTP basic authentication. 203 * @param password the password 204 */ 205 public void setPassword(String password) { 206 for (Authentication auth : authentications.values()) { 207 if (auth instanceof HttpBasicAuth) { 208 ((HttpBasicAuth) auth).setPassword(password); 209 return; 210 } 211 } 212 throw new RuntimeException("No HTTP basic authentication configured!"); 213 } 214 215 /** 216 * Helper method to set API key value for the first API key authentication. 217 * @param apiKey the API key 218 */ 219 public void setApiKey(String apiKey) { 220 for (Authentication auth : authentications.values()) { 221 if (auth instanceof ApiKeyAuth) { 222 ((ApiKeyAuth) auth).setApiKey(apiKey); 223 return; 224 } 225 } 226 throw new RuntimeException("No API key authentication configured!"); 227 } 228 229 /** 230 * Helper method to set API key prefix for the first API key authentication. 231 * @param apiKeyPrefix the API key prefix 232 */ 233 public void setApiKeyPrefix(String apiKeyPrefix) { 234 for (Authentication auth : authentications.values()) { 235 if (auth instanceof ApiKeyAuth) { 236 ((ApiKeyAuth) auth).setApiKeyPrefix(apiKeyPrefix); 237 return; 238 } 239 } 240 throw new RuntimeException("No API key authentication configured!"); 241 } 242 243 {{#hasOAuthMethods}} 244 /** 245 * Helper method to set access token for the first OAuth2 authentication. 246 * @param accessToken the access token 247 */ 248 public void setAccessToken(String accessToken) { 249 for (Authentication auth : authentications.values()) { 250 if (auth instanceof OAuth) { 251 ((OAuth) auth).setAccessToken(accessToken); 252 return; 253 } 254 } 255 throw new RuntimeException("No OAuth2 authentication configured!"); 256 } 257 258 {{/hasOAuthMethods}} 259 /** 260 * Set the User-Agent header's value (by adding to the default header map). 261 * @param userAgent the user agent string 262 * @return ApiClient this client 263 */ 264 public ApiClient setUserAgent(String userAgent) { 265 addDefaultHeader("User-Agent", userAgent); 266 return this; 267 } 268 269 /** 270 * Add a default header. 271 * 272 * @param name The header's name 273 * @param value The header's value 274 * @return ApiClient this client 275 */ 276 public ApiClient addDefaultHeader(String name, String value) { 277 if (defaultHeaders.containsKey(name)) { 278 defaultHeaders.remove(name); 279 } 280 defaultHeaders.add(name, value); 281 return this; 282 } 283 284 /** 285 * Add a default cookie. 286 * 287 * @param name The cookie's name 288 * @param value The cookie's value 289 * @return ApiClient this client 290 */ 291 public ApiClient addDefaultCookie(String name, String value) { 292 if (defaultCookies.containsKey(name)) { 293 defaultCookies.remove(name); 294 } 295 defaultCookies.add(name, value); 296 return this; 297 } 298 299 public void setDebugging(boolean debugging) { 300 List<ClientHttpRequestInterceptor> currentInterceptors = this.restTemplate.getInterceptors(); 301 if(debugging) { 302 if (currentInterceptors == null) { 303 currentInterceptors = new ArrayList<ClientHttpRequestInterceptor>(); 304 } 305 ClientHttpRequestInterceptor interceptor = new ApiClientHttpRequestInterceptor(); 306 currentInterceptors.add(interceptor); 307 this.restTemplate.setInterceptors(currentInterceptors); 308 } else { 309 if (currentInterceptors != null && !currentInterceptors.isEmpty()) { 310 Iterator<ClientHttpRequestInterceptor> iter = currentInterceptors.iterator(); 311 while (iter.hasNext()) { 312 ClientHttpRequestInterceptor interceptor = iter.next(); 313 if (interceptor instanceof ApiClientHttpRequestInterceptor) { 314 iter.remove(); 315 } 316 } 317 this.restTemplate.setInterceptors(currentInterceptors); 318 } 319 } 320 this.debugging = debugging; 321 } 322 323 /** 324 * Check that whether debugging is enabled for this API client. 325 * @return boolean true if this client is enabled for debugging, false otherwise 326 */ 327 public boolean isDebugging() { 328 return debugging; 329 } 330 331 /** 332 * Get the date format used to parse/format date parameters. 333 * @return DateFormat format 334 */ 335 public DateFormat getDateFormat() { 336 return dateFormat; 337 } 338 339 /** 340 * Set the date format used to parse/format date parameters. 341 * @param dateFormat Date format 342 * @return API client 343 */ 344 public ApiClient setDateFormat(DateFormat dateFormat) { 345 this.dateFormat = dateFormat; 346 {{#threetenbp}} 347 for(HttpMessageConverter converter:restTemplate.getMessageConverters()){ 348 if(converter instanceof AbstractJackson2HttpMessageConverter){ 349 ObjectMapper mapper = ((AbstractJackson2HttpMessageConverter)converter).getObjectMapper(); 350 mapper.setDateFormat(dateFormat); 351 } 352 } 353 {{/threetenbp}} 354 return this; 355 } 356 357 /** 358 * Parse the given string into Date object. 359 * @param str the string to parse 360 * @return the Date parsed from the string 361 */ 362 public Date parseDate(String str) { 363 try { 364 return dateFormat.parse(str); 365 } catch (ParseException e) { 366 throw new RuntimeException(e); 367 } 368 } 369 370 /** 371 * Format the given Date object into string. 372 * @param date the date to format 373 * @return the formatted date as string 374 */ 375 public String formatDate(Date date) { 376 return dateFormat.format(date); 377 } 378 379 /** 380 * Format the given parameter object into string. 381 * @param param the object to convert 382 * @return String the parameter represented as a String 383 */ 384 public String parameterToString(Object param) { 385 if (param == null) { 386 return ""; 387 } else if (param instanceof Date) { 388 return formatDate( (Date) param); 389 } else if (param instanceof Collection) { 390 StringBuilder b = new StringBuilder(); 391 for(Object o : (Collection<?>) param) { 392 if(b.length() > 0) { 393 b.append(","); 394 } 395 b.append(String.valueOf(o)); 396 } 397 return b.toString(); 398 } else { 399 return String.valueOf(param); 400 } 401 } 402 403 /** 404 * Formats the specified collection path parameter to a string value. 405 * 406 * @param collectionFormat The collection format of the parameter. 407 * @param values The values of the parameter. 408 * @return String representation of the parameter 409 */ 410 public String collectionPathParameterToString(CollectionFormat collectionFormat, Collection<?> values) { 411 // create the value based on the collection format 412 if (CollectionFormat.MULTI.equals(collectionFormat)) { 413 // not valid for path params 414 return parameterToString(values); 415 } 416 417 // collectionFormat is assumed to be "csv" by default 418 if(collectionFormat == null) { 419 collectionFormat = CollectionFormat.CSV; 420 } 421 422 return collectionFormat.collectionToString(values); 423 } 424 425 /** 426 * Converts a parameter to a {@link MultiValueMap} for use in REST requests 427 * @param collectionFormat The format to convert to 428 * @param name The name of the parameter 429 * @param value The parameter's value 430 * @return a Map containing the String value(s) of the input parameter 431 */ 432 public MultiValueMap<String, String> parameterToMultiValueMap(CollectionFormat collectionFormat, String name, Object value) { 433 final MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>(); 434 435 if (name == null || name.isEmpty() || value == null) { 436 return params; 437 } 438 439 if(collectionFormat == null) { 440 collectionFormat = CollectionFormat.CSV; 441 } 442 443 Collection<?> valueCollection = null; 444 if (value instanceof Collection) { 445 valueCollection = (Collection<?>) value; 446 } else { 447 params.add(name, parameterToString(value)); 448 return params; 449 } 450 451 if (valueCollection.isEmpty()){ 452 return params; 453 } 454 455 if (collectionFormat.equals(CollectionFormat.MULTI)) { 456 for (Object item : valueCollection) { 457 params.add(name, parameterToString(item)); 458 } 459 return params; 460 } 461 462 List<String> values = new ArrayList<String>(); 463 for(Object o : valueCollection) { 464 values.add(parameterToString(o)); 465 } 466 params.add(name, collectionFormat.collectionToString(values)); 467 468 return params; 469 } 470 471 /** 472 * Check if the given {@code String} is a JSON MIME. 473 * @param mediaType the input MediaType 474 * @return boolean true if the MediaType represents JSON, false otherwise 475 */ 476 public boolean isJsonMime(String mediaType) { 477 // "* / *" is default to JSON 478 if ("*/*".equals(mediaType)) { 479 return true; 480 } 481 482 try { 483 return isJsonMime(MediaType.parseMediaType(mediaType)); 484 } catch (InvalidMediaTypeException e) { 485 } 486 return false; 487 } 488 489 /** 490 * Check if the given MIME is a JSON MIME. 491 * JSON MIME examples: 492 * application/json 493 * application/json; charset=UTF8 494 * APPLICATION/JSON 495 * @param mediaType the input MediaType 496 * @return boolean true if the MediaType represents JSON, false otherwise 497 */ 498 public boolean isJsonMime(MediaType mediaType) { 499 return mediaType != null && (MediaType.APPLICATION_JSON.isCompatibleWith(mediaType) || mediaType.getSubtype().matches("^.*\\+json[;]?\\s*$")); 500 } 501 502 /** 503 * Select the Accept header's value from the given accepts array: 504 * if JSON exists in the given array, use it; 505 * otherwise use all of them (joining into a string) 506 * 507 * @param accepts The accepts array to select from 508 * @return List The list of MediaTypes to use for the Accept header 509 */ 510 public List<MediaType> selectHeaderAccept(String[] accepts) { 511 if (accepts.length == 0) { 512 return null; 513 } 514 for (String accept : accepts) { 515 MediaType mediaType = MediaType.parseMediaType(accept); 516 if (isJsonMime(mediaType)) { 517 return Collections.singletonList(mediaType); 518 } 519 } 520 return MediaType.parseMediaTypes(StringUtils.arrayToCommaDelimitedString(accepts)); 521 } 522 523 /** 524 * Select the Content-Type header's value from the given array: 525 * if JSON exists in the given array, use it; 526 * otherwise use the first one of the array. 527 * 528 * @param contentTypes The Content-Type array to select from 529 * @return MediaType The Content-Type header to use. If the given array is empty, JSON will be used. 530 */ 531 public MediaType selectHeaderContentType(String[] contentTypes) { 532 if (contentTypes.length == 0) { 533 return MediaType.APPLICATION_JSON; 534 } 535 for (String contentType : contentTypes) { 536 MediaType mediaType = MediaType.parseMediaType(contentType); 537 if (isJsonMime(mediaType)) { 538 return mediaType; 539 } 540 } 541 return MediaType.parseMediaType(contentTypes[0]); 542 } 543 544 /** 545 * Select the body to use for the request 546 * @param obj the body object 547 * @param formParams the form parameters 548 * @param contentType the content type of the request 549 * @return Object the selected body 550 */ 551 protected Object selectBody(Object obj, MultiValueMap<String, Object> formParams, MediaType contentType) { 552 boolean isForm = MediaType.MULTIPART_FORM_DATA.isCompatibleWith(contentType) || MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType); 553 return isForm ? formParams : obj; 554 } 555 556 /** 557 * Expand path template with variables 558 * @param pathTemplate path template with placeholders 559 * @param variables variables to replace 560 * @return path with placeholders replaced by variables 561 */ 562 public String expandPath(String pathTemplate, Map<String, Object> variables) { 563 return restTemplate.getUriTemplateHandler().expand(pathTemplate, variables).toString(); 564 } 565 566 /** 567 * Invoke API by sending HTTP request with the given options. 568 * 569 * @param <T> the return type to use 570 * @param path The sub-path of the HTTP URL 571 * @param method The request method 572 * @param queryParams The query parameters 573 * @param body The request body object 574 * @param headerParams The header parameters 575 * @param cookieParams The cookie parameters 576 * @param formParams The form parameters 577 * @param accept The request's Accept header 578 * @param contentType The request's Content-Type header 579 * @param authNames The authentications to apply 580 * @param returnType The return type into which to deserialize the response 581 * @return ResponseEntity<T> The response of the chosen type 582 */ 583 public <T> ResponseEntity<T> invokeAPI(String path, HttpMethod method, MultiValueMap<String, String> queryParams, Object body, HttpHeaders headerParams, MultiValueMap<String, String> cookieParams, MultiValueMap<String, Object> formParams, List<MediaType> accept, MediaType contentType, String[] authNames, ParameterizedTypeReference<T> returnType) throws RestClientException { 584 updateParamsForAuth(authNames, queryParams, headerParams, cookieParams); 585 586 final UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(basePath).path(path); 587 if (queryParams != null) { 588 //encode the query parameters in case they contain unsafe characters 589 for (List<String> values : queryParams.values()) { 590 if (values != null) { 591 for (int i = 0; i < values.size(); i++) { 592 try { 593 values.set(i, URLEncoder.encode(values.get(i), "utf8")); 594 } catch (UnsupportedEncodingException e) { 595 596 } 597 } 598 } 599 } 600 builder.queryParams(queryParams); 601 } 602 603 URI uri; 604 try { 605 uri = new URI(builder.build().toUriString()); 606 } catch(URISyntaxException ex) { 607 throw new RestClientException("Could not build URL: " + builder.toUriString(), ex); 608 } 609 610 final BodyBuilder requestBuilder = RequestEntity.method(method, uri); 611 if(accept != null) { 612 requestBuilder.accept(accept.toArray(new MediaType[accept.size()])); 613 } 614 if(contentType != null) { 615 requestBuilder.contentType(contentType); 616 } 617 618 addHeadersToRequest(headerParams, requestBuilder); 619 addHeadersToRequest(defaultHeaders, requestBuilder); 620 addCookiesToRequest(cookieParams, requestBuilder); 621 addCookiesToRequest(defaultCookies, requestBuilder); 622 623 RequestEntity<Object> requestEntity = requestBuilder.body(selectBody(body, formParams, contentType)); 624 625 ResponseEntity<T> responseEntity = restTemplate.exchange(requestEntity, returnType); 626 627 if (responseEntity.getStatusCode().is2xxSuccessful()) { 628 return responseEntity; 629 } else { 630 // The error handler built into the RestTemplate should handle 400 and 500 series errors. 631 throw new RestClientException("API returned " + responseEntity.getStatusCode() + " and it wasn't handled by the RestTemplate error handler"); 632 } 633 } 634 635 /** 636 * Add headers to the request that is being built 637 * @param headers The headers to add 638 * @param requestBuilder The current request 639 */ 640 protected void addHeadersToRequest(HttpHeaders headers, BodyBuilder requestBuilder) { 641 for (Entry<String, List<String>> entry : headers.entrySet()) { 642 List<String> values = entry.getValue(); 643 for(String value : values) { 644 if (value != null) { 645 requestBuilder.header(entry.getKey(), value); 646 } 647 } 648 } 649 } 650 651 /** 652 * Add cookies to the request that is being built 653 * @param cookies The cookies to add 654 * @param requestBuilder The current request 655 */ 656 protected void addCookiesToRequest(MultiValueMap<String, String> cookies, BodyBuilder requestBuilder) { 657 if (!cookies.isEmpty()) { 658 requestBuilder.header("Cookie", buildCookieHeader(cookies)); 659 } 660 } 661 662 /** 663 * Build cookie header. Keeps a single value per cookie (as per <a href="https://tools.ietf.org/html/rfc6265#section-5.3"> 664 * RFC6265 section 5.3</a>). 665 * 666 * @param cookies map all cookies 667 * @return header string for cookies. 668 */ 669 private String buildCookieHeader(MultiValueMap<String, String> cookies) { 670 final StringBuilder cookieValue = new StringBuilder(); 671 String delimiter = ""; 672 for (final Map.Entry<String, List<String>> entry : cookies.entrySet()) { 673 final String value = entry.getValue().get(entry.getValue().size() - 1); 674 cookieValue.append(String.format("%s%s=%s", delimiter, entry.getKey(), value)); 675 delimiter = "; "; 676 } 677 return cookieValue.toString(); 678 } 679 680 /** 681 * Build the RestTemplate used to make HTTP requests. 682 * @return RestTemplate 683 */ 684 protected RestTemplate buildRestTemplate() { 685 {{#withXml}}List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>(); 686 messageConverters.add(new MappingJackson2HttpMessageConverter()); 687 XmlMapper xmlMapper = new XmlMapper(); 688 xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true); 689 xmlMapper.registerModule(new JsonNullableModule()); 690 messageConverters.add(new MappingJackson2XmlHttpMessageConverter(xmlMapper)); 691 692 RestTemplate restTemplate = new RestTemplate(messageConverters); 693 {{/withXml}}{{^withXml}}RestTemplate restTemplate = new RestTemplate();{{/withXml}} 694 {{#threetenbp}} 695 for(HttpMessageConverter converter:restTemplate.getMessageConverters()){ 696 if(converter instanceof AbstractJackson2HttpMessageConverter){ 697 ObjectMapper mapper = ((AbstractJackson2HttpMessageConverter)converter).getObjectMapper(); 698 ThreeTenModule module = new ThreeTenModule(); 699 module.addDeserializer(Instant.class, CustomInstantDeserializer.INSTANT); 700 module.addDeserializer(OffsetDateTime.class, CustomInstantDeserializer.OFFSET_DATE_TIME); 701 module.addDeserializer(ZonedDateTime.class, CustomInstantDeserializer.ZONED_DATE_TIME); 702 mapper.registerModule(module); 703 mapper.registerModule(new JsonNullableModule()); 704 } 705 } 706 {{/threetenbp}} 707 // This allows us to read the response more than once - Necessary for debugging. 708 restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(restTemplate.getRequestFactory())); 709 return restTemplate; 710 } 711 712 /** 713 * Update query and header parameters based on authentication settings. 714 * 715 * @param authNames The authentications to apply 716 * @param queryParams The query parameters 717 * @param headerParams The header parameters 718 */ 719 protected void updateParamsForAuth(String[] authNames, MultiValueMap<String, String> queryParams, HttpHeaders headerParams, MultiValueMap<String, String> cookieParams) { 720 for (String authName : authNames) { 721 Authentication auth = authentications.get(authName); 722 if (auth == null) { 723 throw new RestClientException("Authentication undefined: " + authName); 724 } 725 auth.applyToParams(queryParams, headerParams, cookieParams); 726 } 727 } 728 729 private class ApiClientHttpRequestInterceptor implements ClientHttpRequestInterceptor { 730 private final Log log = LogFactory.getLog(ApiClientHttpRequestInterceptor.class); 731 732 @Override 733 public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { 734 logRequest(request, body); 735 ClientHttpResponse response = execution.execute(request, body); 736 logResponse(response); 737 return response; 738 } 739 740 private void logRequest(HttpRequest request, byte[] body) throws UnsupportedEncodingException { 741 log.info("URI: " + request.getURI()); 742 log.info("HTTP Method: " + request.getMethod()); 743 log.info("HTTP Headers: " + headersToString(request.getHeaders())); 744 log.info("Request Body: " + new String(body, StandardCharsets.UTF_8)); 745 } 746 747 private void logResponse(ClientHttpResponse response) throws IOException { 748 log.info("HTTP Status Code: " + response.getRawStatusCode()); 749 log.info("Status Text: " + response.getStatusText()); 750 log.info("HTTP Headers: " + headersToString(response.getHeaders())); 751 log.info("Response Body: " + bodyToString(response.getBody())); 752 } 753 754 private String headersToString(HttpHeaders headers) { 755 StringBuilder builder = new StringBuilder(); 756 for(Entry<String, List<String>> entry : headers.entrySet()) { 757 builder.append(entry.getKey()).append("=["); 758 for(String value : entry.getValue()) { 759 builder.append(value).append(","); 760 } 761 builder.setLength(builder.length() - 1); // Get rid of trailing comma 762 builder.append("],"); 763 } 764 builder.setLength(builder.length() - 1); // Get rid of trailing comma 765 return builder.toString(); 766 } 767 768 private String bodyToString(InputStream body) throws IOException { 769 StringBuilder builder = new StringBuilder(); 770 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(body, StandardCharsets.UTF_8)); 771 String line = bufferedReader.readLine(); 772 while (line != null) { 773 builder.append(line).append(System.lineSeparator()); 774 line = bufferedReader.readLine(); 775 } 776 bufferedReader.close(); 777 return builder.toString(); 778 } 779 } 780 }