001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.rest.client2; 014 015import static org.apache.juneau.internal.IOUtils.*; 016import static org.apache.juneau.internal.StringUtils.*; 017 018import java.io.*; 019import java.lang.reflect.*; 020import java.nio.charset.*; 021import java.util.concurrent.*; 022import java.util.regex.*; 023 024import org.apache.http.*; 025import org.apache.http.conn.*; 026import org.apache.juneau.*; 027import org.apache.juneau.assertions.*; 028import org.apache.juneau.collections.*; 029import org.apache.juneau.http.*; 030import org.apache.juneau.httppart.*; 031import org.apache.juneau.internal.*; 032import org.apache.juneau.oapi.*; 033import org.apache.juneau.parser.*; 034import org.apache.juneau.parser.ParseException; 035import org.apache.juneau.reflect.*; 036import org.apache.juneau.utils.*; 037 038/** 039 * Represents the body of an HTTP response. 040 * 041 * <p> 042 * An extension of an HttpClient {@link HttpEntity} that provides various support for converting the body to POJOs and 043 * other convenience methods. 044 * 045 * <ul class='seealso'> 046 * <li class='jc'>{@link RestClient} 047 * <li class='link'>{@doc juneau-rest-client} 048 * </ul> 049 */ 050public class RestResponseBody implements HttpEntity { 051 052 private static final HttpEntity NULL_ENTITY = new HttpEntity() { 053 054 @Override 055 public boolean isRepeatable() { 056 return false; 057 } 058 059 @Override 060 public boolean isChunked() { 061 return false; 062 } 063 064 @Override 065 public long getContentLength() { 066 return -1; 067 } 068 069 @Override 070 public Header getContentType() { 071 return RestResponseHeader.NULL_HEADER; 072 } 073 074 @Override 075 public Header getContentEncoding() { 076 return RestResponseHeader.NULL_HEADER; 077 } 078 079 @Override 080 public InputStream getContent() throws IOException, UnsupportedOperationException { 081 return new ByteArrayInputStream(new byte[0]); 082 } 083 084 @Override 085 public void writeTo(OutputStream outstream) throws IOException {} 086 087 @Override 088 public boolean isStreaming() { 089 return false; 090 } 091 092 @Override 093 public void consumeContent() throws IOException {} 094 }; 095 096 private final RestClient client; 097 final RestRequest request; 098 final RestResponse response; 099 private final HttpEntity entity; 100 private HttpPartSchema schema; 101 private Parser parser; 102 private byte[] cache; 103 private boolean cached; 104 boolean isConsumed; 105 106 /** 107 * Constructor. 108 * 109 * @param client The client used to build this request. 110 * @param request The request object. 111 * @param response The response object. 112 * @param parser The parser to use to consume the body. Can be <jk>null</jk>. 113 */ 114 public RestResponseBody(RestClient client, RestRequest request, RestResponse response, Parser parser) { 115 this.client = client; 116 this.request = request; 117 this.response = response; 118 this.parser = parser; 119 this.entity = ObjectUtils.firstNonNull(response.asHttpResponse().getEntity(), NULL_ENTITY); 120 } 121 122 //------------------------------------------------------------------------------------------------------------------ 123 // Setters 124 //------------------------------------------------------------------------------------------------------------------ 125 126 /** 127 * Specifies the parser to use for this body. 128 * 129 * <p> 130 * If not specified, uses the parser defined on the client set via {@link RestClientBuilder#parser(Class)}. 131 * 132 * @param value 133 * The new part parser to use for this body. 134 * @return This object (for method chaining). 135 */ 136 public RestResponseBody parser(Parser value) { 137 this.parser = value; 138 return this; 139 } 140 141 /** 142 * Specifies the schema for this body. 143 * 144 * <p> 145 * Used by schema-based parsers such as {@link OpenApiParser}. 146 * 147 * @param value The schema. 148 * @return This object (for method chaining). 149 */ 150 public RestResponseBody schema(HttpPartSchema value) { 151 this.schema = value; 152 return this; 153 } 154 155 /** 156 * Causes the contents of the response body to be stored so that it can be repeatedly read. 157 * 158 * <p> 159 * Calling this method allows methods that read the response body to be called multiple times. 160 * 161 * <ul class='notes'> 162 * <li> 163 * Multiple calls to this method are ignored. 164 * </ul> 165 * 166 * @return This object (for method chaining). 167 */ 168 public RestResponseBody cache() { 169 this.cached = true; 170 return this; 171 } 172 173 //------------------------------------------------------------------------------------------------------------------ 174 // Raw streams 175 //------------------------------------------------------------------------------------------------------------------ 176 177 /** 178 * Returns the HTTP response message body as an input stream. 179 * 180 * <ul class='notes'> 181 * <li> 182 * Once this input stream is exhausted, it will automatically be closed. 183 * <li> 184 * This method can be called multiple times if {@link #cache()} has been called. 185 * <li> 186 * Calling this method multiple times without caching enabled will cause a {@link RestCallException} 187 * with an inner {@link IllegalStateException} to be thrown. 188 * </ul> 189 * 190 * @return 191 * The HTTP response message body input stream, never <jk>null</jk>. 192 * <br>For responses without a body(e.g. HTTP 204), returns an empty stream. 193 * @throws IOException If a stream or illegal state exception was thrown. 194 */ 195 public InputStream asInputStream() throws IOException { 196 try { 197 if (cache != null) 198 return new ByteArrayInputStream(cache); 199 200 if (cached) { 201 cache = IOUtils.readBytes(entity.getContent()); 202 response.close(); 203 return new ByteArrayInputStream(cache); 204 } 205 206 if (isConsumed && ! entity.isRepeatable()) 207 throw new IllegalStateException("Method cannot be called. Response has already been consumed. Consider using the RestResponse.cacheBody() method."); 208 209 HttpEntity e = response.asHttpResponse().getEntity(); 210 InputStream is = e == null ? new ByteArrayInputStream(new byte[0]) : e.getContent(); 211 212 is = new EofSensorInputStream(is, new EofSensorWatcher() { 213 @Override 214 public boolean eofDetected(InputStream wrapped) throws IOException { 215 try { 216 response.close(); 217 } catch (RestCallException e) {} 218 return true; 219 } 220 @Override 221 public boolean streamClosed(InputStream wrapped) throws IOException { 222 try { 223 response.close(); 224 } catch (RestCallException e) {} 225 return true; 226 } 227 @Override 228 public boolean streamAbort(InputStream wrapped) throws IOException { 229 try { 230 response.close(); 231 } catch (RestCallException e) {} 232 return true; 233 } 234 }); 235 236 isConsumed = true; 237 238 return is; 239 } catch (UnsupportedOperationException | RestCallException e) { 240 throw new IOException(e); 241 } 242 } 243 244 /** 245 * Returns the HTTP response message body as a reader based on the charset on the <code>Content-Type</code> response header. 246 * 247 * <ul class='notes'> 248 * <li> 249 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 250 * <li> 251 * Once this input stream is exhausted, it will automatically be closed. 252 * <li> 253 * This method can be called multiple times if {@link #cache()} has been called. 254 * <li> 255 * Calling this method multiple times without caching enabled will cause a {@link RestCallException} 256 * with an inner {@link IllegalStateException} to be thrown. 257 * </ul> 258 * 259 * @return 260 * The HTTP response message body reader, never <jk>null</jk>. 261 * <br>For responses without a body(e.g. HTTP 204), returns an empty reader. 262 * @throws IOException If an exception occurred. 263 */ 264 public Reader asReader() throws IOException { 265 266 // Figure out what the charset of the response is. 267 String cs = null; 268 String ct = getContentType().asString(); 269 270 // First look for "charset=" in Content-Type header of response. 271 if (ct != null) 272 if (ct.contains("charset=")) 273 cs = ct.substring(ct.indexOf("charset=")+8).trim(); 274 275 return asReader(cs == null ? IOUtils.UTF8 : Charset.forName(cs)); 276 } 277 278 /** 279 * Returns the HTTP response message body as a reader using the specified charset. 280 * 281 * <ul class='notes'> 282 * <li> 283 * Once this input stream is exhausted, it will automatically be closed. 284 * <li> 285 * This method can be called multiple times if {@link #cache()} has been called. 286 * <li> 287 * Calling this method multiple times without caching enabled will cause a {@link RestCallException} 288 * with an inner {@link IllegalStateException} to be thrown. 289 * </ul> 290 * 291 * @param charset 292 * The charset to use for the reader. 293 * <br>If <jk>null</jk>, <js>"UTF-8"</js> is used. 294 * @return 295 * The HTTP response message body reader, never <jk>null</jk>. 296 * <br>For responses without a body(e.g. HTTP 204), returns an empty reader. 297 * @throws IOException If an exception occurred. 298 */ 299 public Reader asReader(Charset charset) throws IOException { 300 return new InputStreamReader(asInputStream(), charset == null ? IOUtils.UTF8 : charset); 301 } 302 303 /** 304 * Returns the HTTP response message body as a byte array. 305 * 306 * The HTTP response message body reader, never <jk>null</jk>. 307 * <br>For responses without a body(e.g. HTTP 204), returns an empty array. 308 * 309 * @return The HTTP response body as a byte array. 310 * @throws RestCallException If an exception occurred. 311 */ 312 public byte[] asBytes() throws RestCallException { 313 if (cache == null) { 314 try { 315 cache = IOUtils.readBytes(entity.getContent()); 316 } catch (IOException e) { 317 throw new RestCallException(response, e, "Could not read response body."); 318 } finally { 319 response.close(); 320 } 321 } 322 return cache; 323 } 324 325 326 /** 327 * Pipes the contents of the response to the specified output stream. 328 * 329 * <ul class='notes'> 330 * <li> 331 * The output stream is not automatically closed. 332 * <li> 333 * Once the input stream is exhausted, it will automatically be closed. 334 * <li> 335 * This method can be called multiple times if {@link #cache()} has been called. 336 * <li> 337 * Calling this method multiple times without caching enabled will cause a {@link RestCallException} 338 * with an inner {@link IllegalStateException} to be thrown. 339 * </ul> 340 * 341 * @param os The output stream to pipe the output to. 342 * @return The response object (for method chaining). 343 * @throws IOException If an IO exception occurred. 344 */ 345 public RestResponse pipeTo(OutputStream os) throws IOException { 346 IOPipe.create(asInputStream(), os).run(); 347 return response; 348 } 349 350 /** 351 * Pipes the contents of the response to the specified writer. 352 * 353 * <ul class='notes'> 354 * <li> 355 * The writer is not automatically closed. 356 * <li> 357 * Once the reader is exhausted, it will automatically be closed. 358 * <li> 359 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 360 * <li> 361 * This method can be called multiple times if {@link #cache()} has been called. 362 * <li> 363 * Calling this method multiple times without caching enabled will cause a {@link RestCallException} 364 * with an inner {@link IllegalStateException} to be thrown. 365 * </ul> 366 * 367 * @param w The writer to pipe the output to. 368 * @return The response object (for method chaining). 369 * @throws IOException If an IO exception occurred. 370 */ 371 public RestResponse pipeTo(Writer w) throws IOException { 372 return pipeTo(w, false); 373 } 374 375 /** 376 * Pipes the contents of the response to the specified writer. 377 * 378 * <ul class='notes'> 379 * <li> 380 * The writer is not automatically closed. 381 * <li> 382 * Once the reader is exhausted, it will automatically be closed. 383 * <li> 384 * This method can be called multiple times if {@link #cache()} has been called. 385 * <li> 386 * Calling this method multiple times without caching enabled will cause a {@link RestCallException} 387 * with an inner {@link IllegalStateException} to be thrown. 388 * </ul> 389 * 390 * @param w The writer to pipe the output to. 391 * @param charset 392 * The charset to use for the reader. 393 * <br>If <jk>null</jk>, <js>"UTF-8"</js> is used. 394 * @return The response object (for method chaining). 395 * @throws IOException If an IO exception occurred. 396 */ 397 public RestResponse pipeTo(Writer w, Charset charset) throws IOException { 398 return pipeTo(w, charset, false); 399 } 400 401 /** 402 * Pipes the contents of the response to the specified writer. 403 * 404 * <ul class='notes'> 405 * <li> 406 * The writer is not automatically closed. 407 * <li> 408 * Once the reader is exhausted, it will automatically be closed. 409 * <li> 410 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 411 * <li> 412 * This method can be called multiple times if {@link #cache()} has been called. 413 * <li> 414 * Calling this method multiple times without caching enabled will cause a {@link RestCallException} 415 * with an inner {@link IllegalStateException} to be thrown. 416 * </ul> 417 * 418 * @param w The writer to write the output to. 419 * @param byLines Flush the writers after every line of output. 420 * @return The response object (for method chaining). 421 * @throws IOException If an IO exception occurred. 422 */ 423 public RestResponse pipeTo(Writer w, boolean byLines) throws IOException { 424 return pipeTo(w, null, byLines); 425 } 426 427 /** 428 * Pipes the contents of the response to the specified writer. 429 * 430 * <ul class='notes'> 431 * <li> 432 * The writer is not automatically closed. 433 * <li> 434 * Once the reader is exhausted, it will automatically be closed. 435 * <li> 436 * This method can be called multiple times if {@link #cache()} has been called. 437 * <li> 438 * Calling this method multiple times without caching enabled will cause a {@link RestCallException} 439 * with an inner {@link IllegalStateException} to be thrown. 440 * </ul> 441 * 442 * @param w The writer to pipe the output to. 443 * @param byLines Flush the writers after every line of output. 444 * @param charset 445 * The charset to use for the reader. 446 * <br>If <jk>null</jk>, <js>"UTF-8"</js> is used. 447 * @return The response object (for method chaining). 448 * @throws IOException If an IO exception occurred. 449 */ 450 public RestResponse pipeTo(Writer w, Charset charset, boolean byLines) throws IOException { 451 IOPipe.create(asReader(charset), w).byLines(byLines).run(); 452 return response; 453 } 454 455 //------------------------------------------------------------------------------------------------------------------ 456 // Retrievers 457 //------------------------------------------------------------------------------------------------------------------ 458 459 /** 460 * Parses HTTP body into the specified object type. 461 * 462 * <p> 463 * The type can be a simple type (e.g. beans, strings, numbers) or parameterized type (collections/maps). 464 * 465 * <h5 class='section'>Examples:</h5> 466 * <p class='bcode w800'> 467 * <jc>// Parse into a linked-list of strings.</jc> 468 * List<String> <jv>l1</jv> = <jv>client</jv> 469 * .get(<jsf>URI</jsf>) 470 * .run() 471 * .getBody().as(LinkedList.<jk>class</jk>, String.<jk>class</jk>); 472 * 473 * <jc>// Parse into a linked-list of beans.</jc> 474 * List<MyBean> <jv>l2</jv> = <jv>client</jv> 475 * .get(<jsf>URI</jsf>) 476 * .run() 477 * .getBody().as(LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>); 478 * 479 * <jc>// Parse into a linked-list of linked-lists of strings.</jc> 480 * List<List<String>> <jv>l3</jv> = <jv>client</jv> 481 * .get(<jsf>URI</jsf>) 482 * .run() 483 * .getBody().as(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>); 484 * 485 * <jc>// Parse into a map of string keys/values.</jc> 486 * Map<String,String> <jv>m1</jv> = <jv>client</jv> 487 * .get(<jsf>URI</jsf>) 488 * .run() 489 * .getBody().as(TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>); 490 * 491 * <jc>// Parse into a map containing string keys and values of lists containing beans.</jc> 492 * Map<String,List<MyBean>> <jv>m2</jv> = <jv>client</jv> 493 * .get(<jsf>URI</jsf>) 494 * .run() 495 * .getBody().as(TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>); 496 * </p> 497 * 498 * <p> 499 * <c>Collection</c> classes are assumed to be followed by zero or one objects indicating the element type. 500 * 501 * <p> 502 * <c>Map</c> classes are assumed to be followed by zero or two meta objects indicating the key and value types. 503 * 504 * <p> 505 * The array can be arbitrarily long to indicate arbitrarily complex data structures. 506 * 507 * <ul class='notes'> 508 * <li> 509 * Use the {@link #as(Class)} method instead if you don't need a parameterized map/collection. 510 * <li> 511 * You can also specify any of the following types: 512 * <ul class='compact'> 513 * <li>{@link RestResponseBody}/{@link HttpEntity} - Returns access to this object. 514 * <li>{@link Reader} - Returns access to the raw reader of the response. 515 * <li>{@link InputStream} - Returns access to the raw input stream of the response. 516 * <li>{@link BasicHttpResource} - Raw contents will be serialized to remote resource. Additional headers and media type will be set on request. 517 * </ul> 518 * <li> 519 * If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with 520 * other methods that retrieve the content of the response. Otherwise a {@link RestCallException} 521 * with an inner {@link IllegalStateException} will be thrown. 522 * <li> 523 * The input stream is automatically closed after this call. 524 * </ul> 525 * 526 * @param <T> The class type of the object to create. 527 * @param type 528 * The object type to create. 529 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 530 * @param args 531 * The type arguments of the class if it's a collection or map. 532 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 533 * <br>Ignored if the main type is not a map or collection. 534 * @return The parsed object. 535 * @throws RestCallException 536 * <ul> 537 * <li>If the input contains a syntax error or is malformed, or is not valid for the specified type. 538 * <li>If a connection error occurred. 539 * </ul> 540 * @see BeanSession#getClassMeta(Class) for argument syntax for maps and collections. 541 */ 542 public <T> T as(Type type, Type...args) throws RestCallException { 543 return as(getClassMeta(type, args)); 544 } 545 546 /** 547 * Same as {@link #as(Type,Type...)} but sets the value in a mutable for fluent calls. 548 * 549 * <h5 class='section'>Example:</h5> 550 * <p class='bcode w800'> 551 * <jc>// Parse into a linked-list of strings and also pipe to an output stream.</jc> 552 * Mutable<List<String>> <jv>mutable</jv> = Mutable.<jsm>create()</jsm>; 553 * 554 * <jv>client</jv> 555 * .get(<jsf>URI</jsf>) 556 * .run() 557 * .cache() 558 * .getBody().as(<jv>mutable</jv>, LinkedList.<jk>class</jk>, String.<jk>class</jk>) 559 * .getBody().pipeTo(outputStream) 560 * .assertStatus().is(200); 561 * 562 * List<String> <jv>list</jv> = <jv>mutable</jv>.get(); 563 * </p> 564 * 565 * <ul class='notes'> 566 * <li> 567 * If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with 568 * other methods that retrieve the content of the response. Otherwise a {@link RestCallException} 569 * with an inner {@link IllegalStateException} will be thrown. 570 * <li> 571 * The input stream is automatically closed after this call. 572 * </ul> 573 * 574 * @param <T> The class type of the object to create. 575 * @param m The mutable to set the parsed value in. 576 * @param type 577 * The object type to create. 578 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 579 * @param args 580 * The type arguments of the class if it's a collection or map. 581 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 582 * <br>Ignored if the main type is not a map or collection. 583 * @return The response object (for method chaining). 584 * @throws RestCallException 585 * <ul> 586 * <li>If the input contains a syntax error or is malformed, or is not valid for the specified type. 587 * <li>If a connection error occurred. 588 * </ul> 589 * @see BeanSession#getClassMeta(Class) for argument syntax for maps and collections. 590 */ 591 public <T> RestResponse as(Mutable<T> m, Type type, Type...args) throws RestCallException { 592 m.set(as(type, args)); 593 return response; 594 } 595 596 /** 597 * Same as {@link #as(Type,Type...)} except optimized for a non-parameterized class. 598 * 599 * <p> 600 * This is the preferred parse method for simple types since you don't need to cast the results. 601 * 602 * <h5 class='section'>Examples:</h5> 603 * <p class='bcode w800'> 604 * <jc>// Parse into a string.</jc> 605 * String <jv>string</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().as(String.<jk>class</jk>); 606 * 607 * <jc>// Parse into a bean.</jc> 608 * MyBean <jv>bean</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().as(MyBean.<jk>class</jk>); 609 * 610 * <jc>// Parse into a bean array.</jc> 611 * MyBean[] <jv>beanArray</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().as(MyBean[].<jk>class</jk>); 612 * 613 * <jc>// Parse into a linked-list of objects.</jc> 614 * List <jv>list</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().as(LinkedList.<jk>class</jk>); 615 * 616 * <jc>// Parse into a map of object keys/values.</jc> 617 * Map <jv>map</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().as(TreeMap.<jk>class</jk>); 618 * </p> 619 * 620 * <ul class='notes'> 621 * <li> 622 * You can also specify any of the following types: 623 * <ul class='compact'> 624 * <li>{@link RestResponseBody}/{@link HttpEntity} - Returns access to this object. 625 * <li>{@link Reader} - Returns access to the raw reader of the response. 626 * <li>{@link InputStream} - Returns access to the raw input stream of the response. 627 * <li>{@link BasicHttpResource} - Raw contents will be serialized to remote resource. Additional headers and media type will be set on request. 628 * </ul> 629 * <li> 630 * If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with 631 * other methods that retrieve the content of the response. Otherwise a {@link RestCallException} 632 * with an inner {@link IllegalStateException} will be thrown. 633 * <li> 634 * The input stream is automatically closed after this call. 635 * </ul> 636 * 637 * @param <T> 638 * The class type of the object being created. 639 * See {@link #as(Type,Type...)} for details. 640 * @param type The object type to create. 641 * @return The parsed object. 642 * @throws RestCallException 643 * If the input contains a syntax error or is malformed, or is not valid for the specified type, or if a connection 644 * error occurred. 645 */ 646 public <T> T as(Class<T> type) throws RestCallException { 647 return as(getClassMeta(type)); 648 } 649 650 /** 651 * Same as {@link #as(Class)} but sets the value in a mutable for fluent calls. 652 * 653 * <h5 class='section'>Example:</h5> 654 * <p class='bcode w800'> 655 * <jc>// Parse into a bean and also pipe to an output stream.</jc> 656 * Mutable<MyBean> <jv>mutable</jv> = Mutable.<jsm>create()</jsm>; 657 * 658 * <jv>client</jv> 659 * .get(<jsf>URI</jsf>) 660 * .run() 661 * .cache() 662 * .getBody().as(<jv>mutable</jv>, MyBean.<jk>class</jk>) 663 * .getBody().pipeTo(<jv>outputStream</jv>) 664 * .assertStatus().is(200); 665 * 666 * MyBean <jv>bean</jv> = <jv>mutable</jv>.get(); 667 * </p> 668 * 669 * <ul class='notes'> 670 * <li> 671 * If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with 672 * other methods that retrieve the content of the response. Otherwise a {@link RestCallException} 673 * with an inner {@link IllegalStateException} will be thrown. 674 * <li> 675 * The input stream is automatically closed after this call. 676 * </ul> 677 * 678 * @param <T> The class type of the object to create. 679 * @param m The mutable to set the parsed value in. 680 * @param type 681 * The object type to create. 682 * @return The response object (for method chaining). 683 * @throws RestCallException 684 * <ul> 685 * <li>If the input contains a syntax error or is malformed, or is not valid for the specified type. 686 * <li>If a connection error occurred. 687 * </ul> 688 * @see BeanSession#getClassMeta(Class) for argument syntax for maps and collections. 689 */ 690 public <T> RestResponse as(Mutable<T> m, Class<T> type) throws RestCallException { 691 m.set(as(type)); 692 return response; 693 } 694 695 /** 696 * Same as {@link #as(Class)} except allows you to predefine complex data types using the {@link ClassMeta} API. 697 * 698 * <h5 class='section'>Examples:</h5> 699 * <p class='bcode w800'> 700 * BeanContext <jv>bc</jv> = BeanContext.<jsf>DEFAULT</jsf>; 701 * 702 * <jc>// Parse into a linked-list of strings.</jc> 703 * ClassMeta<List<String>> <jv>cm1</jv> = <jv>bc</jv>.getClassMeta(LinkedList.<jk>class</jk>, String.<jk>class</jk>); 704 * List<String> <jv>l1</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().as(<jv>cm1</jv>); 705 * 706 * <jc>// Parse into a linked-list of beans.</jc> 707 * ClassMeta<List<String>> <jv>cm2</jv> = <jv>bc</jv>.getClassMeta(LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>); 708 * List<MyBean> <jv>l2</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().as(<jv>cm2</jv>); 709 * 710 * <jc>// Parse into a linked-list of linked-lists of strings.</jc> 711 * ClassMeta<List<String>> <jv>cm3</jv> = <jv>bc</jv>.getClassMeta(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>); 712 * List<List<String>> <jv>l3</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().as(<jv>cm3</jv>); 713 * 714 * <jc>// Parse into a map of string keys/values.</jc> 715 * ClassMeta<List<String>> <jv>cm4</jv> = <jv>bc</jv>.getClassMeta(TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>); 716 * Map<String,String> <jv>m4</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().as(<jv>cm4</jv>); 717 * 718 * <jc>// Parse into a map containing string keys and values of lists containing beans.</jc> 719 * ClassMeta<List<String>> <jv>cm5</jv> = <jv>bc</jv>.getClassMeta(TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>); 720 * Map<String,List<MyBean>> <jv>m5</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().as(<jv>cm5</jv>); 721 * </p> 722 * 723 * <ul class='notes'> 724 * <li> 725 * If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with 726 * other methods that retrieve the content of the response. Otherwise a {@link RestCallException} 727 * with an inner {@link IllegalStateException} will be thrown. 728 * <li> 729 * The input stream is automatically closed after this call. 730 * </ul> 731 * 732 * @param <T> The class type of the object to create. 733 * @param type The object type to create. 734 * @return The parsed object. 735 * @throws RestCallException 736 * <ul> 737 * <li>If the input contains a syntax error or is malformed, or is not valid for the specified type. 738 * <li>If a connection error occurred. 739 * </ul> 740 * @see BeanSession#getClassMeta(Class) for argument syntax for maps and collections. 741 */ 742 @SuppressWarnings("unchecked") 743 public <T> T as(ClassMeta<T> type) throws RestCallException { 744 try { 745 Class<?> ic = type.getInnerClass(); 746 747 if (ic.equals(RestResponseBody.class) || ic.equals(HttpEntity.class)) 748 return (T)this; 749 750 if (ic.equals(Reader.class)) 751 return (T)asReader(); 752 753 if (ic.equals(InputStream.class)) 754 return (T)asInputStream(); 755 756 if (type.isType(HttpResponse.class)) 757 return (T)response; 758 759 if (type.isType(HttpResource.class)) { 760 BasicHttpResource r = BasicHttpResource.of(asInputStream()); 761 for (Header h : response.getAllHeaders()) { 762 if (h.getName().equalsIgnoreCase("Content-Type")) 763 r.contentType(h); 764 else if (h.getName().equalsIgnoreCase("Content-Encoding")) 765 r.contentEncoding(h); 766 else 767 r.header(h); 768 } 769 return (T)r; 770 } 771 772 String ct = firstNonEmpty(response.getHeader("Content-Type").asStringOrElse("text/plain")); 773 774 if (parser == null) 775 parser = client.getMatchingParser(ct); 776 777 MediaType mt = MediaType.of(ct); 778 779 if (parser == null || (mt.toString().equals("text/plain") && ! parser.canHandle(ct))) { 780 if (type.hasStringMutater()) 781 return type.getStringMutater().mutate(asString()); 782 } 783 784 if (parser != null) { 785 try (Closeable in = parser.isReaderParser() ? asReader() : asInputStream()) { 786 787 ParserSessionArgs pArgs = 788 ParserSessionArgs 789 .create() 790 .properties(new OMap().inner(request.getProperties())) 791 .locale(response.getLocale()) 792 .mediaType(mt) 793 .schema(schema); 794 795 T t = parser.createSession(pArgs).parse(in, type); 796 797 // Some HTTP responses have no body, so try to create these beans if they've got no-arg constructors. 798 if (t == null && ! type.isType(String.class)) { 799 ConstructorInfo c = type.getInfo().getPublicConstructor(); 800 if (c != null) { 801 try { 802 return c.<T>invoke(); 803 } catch (ExecutableException e) { 804 throw new ParseException(e); 805 } 806 } 807 } 808 809 return t; 810 } 811 } 812 813 if (type.hasReaderMutater()) 814 return type.getReaderMutater().mutate(asReader()); 815 816 if (type.hasInputStreamMutater()) 817 return type.getInputStreamMutater().mutate(asInputStream()); 818 819 throw new ParseException( 820 "Unsupported media-type in request header ''Content-Type'': ''{0}''", 821 response.getStringHeader("Content-Type") 822 ); 823 824 } catch (ParseException | IOException e) { 825 response.close(); 826 throw new RestCallException(response, e, "Could not parse response body."); 827 } 828 } 829 830 /** 831 * Identical to {@link #as(ClassMeta)} but sets the value in a mutable for fluent calls. 832 * 833 * <h5 class='section'>Example:</h5> 834 * <p class='bcode w800'> 835 * <jc>// Parse into a bean and also pipe to an output stream.</jc> 836 * Mutable<List<MyBean>> <jv>mutable</jv> = Mutable.<jsm>create()</jsm>; 837 * ClassMeta<List<MyBean>> <jv>cm</jv> = BeanContext.<jsf>DEFAULT</jsf>.getClassMeta(LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>); 838 * 839 * <jv>client</jv> 840 * .get(<jsf>URI</jsf>) 841 * .run() 842 * .cache() 843 * .getBody().as(<jv>mutable</jv>, <jv>cm</jv>) 844 * .getBody().pipeTo(<jv>outputStream</jv>) 845 * .assertStatus().is(200); 846 * 847 * MyBean <jv>bean</jv> = <jv>mutable</jv>.get(); 848 * </p> 849 * 850 * <ul class='notes'> 851 * <li> 852 * If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with 853 * other methods that retrieve the content of the response. Otherwise a {@link RestCallException} 854 * with an inner {@link IllegalStateException} will be thrown. 855 * <li> 856 * The input stream is automatically closed after this call. 857 * </ul> 858 * 859 * @param <T> The class type of the object to create. 860 * @param m The mutable to set the parsed value in. 861 * @param type 862 * The object type to create. 863 * @return The response object (for method chaining). 864 * @throws RestCallException 865 * <ul> 866 * <li>If the input contains a syntax error or is malformed, or is not valid for the specified type. 867 * <li>If a connection error occurred. 868 * </ul> 869 * @see BeanSession#getClassMeta(Class) for argument syntax for maps and collections. 870 */ 871 public <T> RestResponse as(Mutable<T> m, ClassMeta<T> type) throws RestCallException { 872 m.set(as(type)); 873 return response; 874 } 875 876 /** 877 * Same as {@link #as(Class)} but allows you to run the call asynchronously. 878 * 879 * <ul class='notes'> 880 * <li> 881 * If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with 882 * other methods that retrieve the content of the response. Otherwise a {@link RestCallException} 883 * with an inner {@link IllegalStateException} will be thrown. 884 * <li> 885 * The input stream is automatically closed after the execution of the future. 886 * </ul> 887 * 888 * @param <T> The class type of the object being created. 889 * @param type The object type to create. 890 * @return The future object. 891 * @throws RestCallException If the executor service was not defined. 892 * @see 893 * RestClientBuilder#executorService(ExecutorService, boolean) for defining the executor service for creating 894 * {@link Future Futures}. 895 */ 896 public <T> Future<T> asFuture(final Class<T> type) throws RestCallException { 897 return client.getExecutorService().submit( 898 new Callable<T>() { 899 @Override /* Callable */ 900 public T call() throws Exception { 901 return as(type); 902 } 903 } 904 ); 905 } 906 907 /** 908 * Same as {@link #as(Mutable,Class)} but allows you to run the call asynchronously. 909 * 910 * <ul class='notes'> 911 * <li> 912 * If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with 913 * other methods that retrieve the content of the response. Otherwise a {@link RestCallException} 914 * with an inner {@link IllegalStateException} will be thrown. 915 * <li> 916 * The input stream is automatically closed after the execution of the future. 917 * </ul> 918 * 919 * @param <T> The class type of the object being created. 920 * @param m The mutable to set the parsed value in. 921 * @param type The object type to create. 922 * @return The response object (for method chaining). 923 * @throws RestCallException If the executor service was not defined. 924 * @see 925 * RestClientBuilder#executorService(ExecutorService, boolean) for defining the executor service for creating 926 * {@link Future Futures}. 927 */ 928 public <T> RestResponse asFuture(Mutable<Future<T>> m, Class<T> type) throws RestCallException { 929 m.set(asFuture(type)); 930 return response; 931 } 932 933 /** 934 * Same as {@link #as(ClassMeta)} but allows you to run the call asynchronously. 935 * 936 * <ul class='notes'> 937 * <li> 938 * If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with 939 * other methods that retrieve the content of the response. Otherwise a {@link RestCallException} 940 * with an inner {@link IllegalStateException} will be thrown. 941 * <li> 942 * The input stream is automatically closed after the execution of the future. 943 * </ul> 944 * 945 * @param <T> 946 * The class type of the object being created. 947 * See {@link #as(Type, Type...)} for details. 948 * @param type The object type to create. 949 * @return The future object. 950 * @throws RestCallException If the executor service was not defined. 951 * @see 952 * RestClientBuilder#executorService(ExecutorService, boolean) for defining the executor service for creating 953 * {@link Future Futures}. 954 */ 955 public <T> Future<T> asFuture(final ClassMeta<T> type) throws RestCallException { 956 return client.getExecutorService().submit( 957 new Callable<T>() { 958 @Override /* Callable */ 959 public T call() throws Exception { 960 return as(type); 961 } 962 } 963 ); 964 } 965 966 /** 967 * Same as {@link #as(Mutable,ClassMeta)} but allows you to run the call asynchronously. 968 * 969 * <ul class='notes'> 970 * <li> 971 * If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with 972 * other methods that retrieve the content of the response. Otherwise a {@link RestCallException} 973 * with an inner {@link IllegalStateException} will be thrown. 974 * <li> 975 * The input stream is automatically closed after the execution of the future. 976 * </ul> 977 * 978 * @param <T> 979 * The class type of the object being created. 980 * See {@link #as(Type, Type...)} for details. 981 * @param m The mutable to set the parsed value in. 982 * @param type The object type to create. 983 * @return The response object (for method chaining). 984 * @throws RestCallException If the executor service was not defined. 985 * @see 986 * RestClientBuilder#executorService(ExecutorService, boolean) for defining the executor service for creating 987 * {@link Future Futures}. 988 */ 989 public <T> RestResponse asFuture(Mutable<Future<T>>m, ClassMeta<T> type) throws RestCallException { 990 m.set(asFuture(type)); 991 return response; 992 } 993 994 /** 995 * Same as {@link #as(Type,Type...)} but allows you to run the call asynchronously. 996 * 997 * <ul class='notes'> 998 * <li> 999 * If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with 1000 * other methods that retrieve the content of the response. Otherwise a {@link RestCallException} 1001 * with an inner {@link IllegalStateException} will be thrown. 1002 * <li> 1003 * The input stream is automatically closed after the execution of the future. 1004 * </ul> 1005 * 1006 * @param <T> 1007 * The class type of the object being created. 1008 * See {@link #as(Type, Type...)} for details. 1009 * @param type 1010 * The object type to create. 1011 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 1012 * @param args 1013 * The type arguments of the class if it's a collection or map. 1014 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 1015 * <br>Ignored if the main type is not a map or collection. 1016 * @return The future object. 1017 * @throws RestCallException If the executor service was not defined. 1018 * @see 1019 * RestClientBuilder#executorService(ExecutorService, boolean) for defining the executor service for creating 1020 * {@link Future Futures}. 1021 */ 1022 public <T> Future<T> asFuture(final Type type, final Type...args) throws RestCallException { 1023 return client.getExecutorService().submit( 1024 new Callable<T>() { 1025 @Override /* Callable */ 1026 public T call() throws Exception { 1027 return as(type, args); 1028 } 1029 } 1030 ); 1031 } 1032 1033 /** 1034 * Same as {@link #as(Mutable,Type,Type...)} but allows you to run the call asynchronously. 1035 * 1036 * <ul class='notes'> 1037 * <li> 1038 * If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with 1039 * other methods that retrieve the content of the response. Otherwise a {@link RestCallException} 1040 * with an inner {@link IllegalStateException} will be thrown. 1041 * <li> 1042 * The input stream is automatically closed after the execution of the future. 1043 * </ul> 1044 * 1045 * @param <T> 1046 * The class type of the object being created. 1047 * See {@link #as(Type, Type...)} for details. 1048 * @param m The mutable to set the parsed value in. 1049 * @param type 1050 * The object type to create. 1051 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 1052 * @param args 1053 * The type arguments of the class if it's a collection or map. 1054 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 1055 * <br>Ignored if the main type is not a map or collection. 1056 * @return The response object (for method chaining). 1057 * @throws RestCallException If the executor service was not defined. 1058 * @see 1059 * RestClientBuilder#executorService(ExecutorService, boolean) for defining the executor service for creating 1060 * {@link Future Futures}. 1061 */ 1062 public <T> RestResponse asFuture(Mutable<Future<T>> m, Type type, Type...args) throws RestCallException { 1063 m.set(asFuture(type, args)); 1064 return response; 1065 } 1066 1067 /** 1068 * Returns the contents of this body as a string. 1069 * 1070 * <ul class='notes'> 1071 * <li> 1072 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 1073 * <li> 1074 * This method automatically calls {@link #cache()} so that the body can be retrieved multiple times. 1075 * <li> 1076 * The input stream is automatically closed after this call. 1077 * </ul> 1078 * 1079 * @return The response as a string. 1080 * @throws RestCallException 1081 * <ul> 1082 * <li>If the input contains a syntax error or is malformed, or is not valid for the specified type. 1083 * <li>If a connection error occurred. 1084 * </ul> 1085 */ 1086 public String asString() throws RestCallException { 1087 cache(); 1088 try (Reader r = asReader()) { 1089 return read(r).toString(); 1090 } catch (IOException e) { 1091 response.close(); 1092 throw new RestCallException(response, e, "Could not read response body."); 1093 } 1094 } 1095 1096 /** 1097 * Same as {@link #asString()} but sets the value in a mutable for fluent calls. 1098 * 1099 * <ul class='notes'> 1100 * <li> 1101 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 1102 * <li> 1103 * This method automatically calls {@link #cache()} so that the body can be retrieved multiple times. 1104 * <li> 1105 * The input stream is automatically closed after this call. 1106 * </ul> 1107 * 1108 * @param m The mutable to set the value in. 1109 * @return The response object (for method chaining). 1110 * @throws RestCallException 1111 * <ul> 1112 * <li>If a connection error occurred. 1113 * </ul> 1114 */ 1115 public RestResponse asString(Mutable<String> m) throws RestCallException { 1116 m.set(asString()); 1117 return response; 1118 } 1119 1120 /** 1121 * Same as {@link #asString()} but allows you to run the call asynchronously. 1122 * 1123 * <ul class='notes'> 1124 * <li> 1125 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 1126 * <li> 1127 * This method automatically calls {@link #cache()} so that the body can be retrieved multiple times. 1128 * <li> 1129 * The input stream is automatically closed after this call. 1130 * </ul> 1131 * 1132 * @return The future object. 1133 * @throws RestCallException If the executor service was not defined. 1134 * @see 1135 * RestClientBuilder#executorService(ExecutorService, boolean) for defining the executor service for creating 1136 * {@link Future Futures}. 1137 */ 1138 public Future<String> asStringFuture() throws RestCallException { 1139 return client.getExecutorService().submit( 1140 new Callable<String>() { 1141 @Override /* Callable */ 1142 public String call() throws Exception { 1143 return asString(); 1144 } 1145 } 1146 ); 1147 } 1148 1149 /** 1150 * Same as {@link #asStringFuture()} but sets the value in a mutable for fluent calls. 1151 * 1152 * <ul class='notes'> 1153 * <li> 1154 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 1155 * <li> 1156 * If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with 1157 * other methods that retrieve the content of the response. Otherwise a {@link RestCallException} 1158 * with an inner {@link IllegalStateException} will be thrown. 1159 * <li> 1160 * The input stream is automatically closed after this call. 1161 * </ul> 1162 * 1163 * @param m The mutable to set the value in. 1164 * @return The response object (for method chaining). 1165 * @throws RestCallException If the executor service was not defined. 1166 * @see 1167 * RestClientBuilder#executorService(ExecutorService, boolean) for defining the executor service for creating 1168 * {@link Future Futures}. 1169 */ 1170 public RestResponse asStringFuture(Mutable<Future<String>> m) throws RestCallException { 1171 m.set(asStringFuture()); 1172 return response; 1173 } 1174 1175 /** 1176 * Same as {@link #asString()} but truncates the string to the specified length. 1177 * 1178 * <p> 1179 * If truncation occurs, the string will be suffixed with <js>"..."</js>. 1180 * 1181 * @param length The max length of the returned string. 1182 * @return The truncated string. 1183 * @throws RestCallException 1184 * <ul> 1185 * <li>If a connection error occurred. 1186 * </ul> 1187 */ 1188 public String asAbbreviatedString(int length) throws RestCallException { 1189 return StringUtils.abbreviate(asString(), length); 1190 } 1191 1192 /** 1193 * Same as {@link #asAbbreviatedString(int)} but sets the value in a mutable for fluent calls. 1194 * 1195 * <p> 1196 * If truncation occurs, the string will be suffixed with <js>"..."</js>. 1197 * 1198 * @param m The mutable to set the value in. 1199 * @param length The max length of the returned string. 1200 * @return The response object (for method chaining). 1201 * @throws RestCallException 1202 * <ul> 1203 * <li>If a connection error occurred. 1204 * </ul> 1205 */ 1206 public RestResponse asAbbreviatedString(Mutable<String> m, int length) throws RestCallException { 1207 m.set(asAbbreviatedString(length)); 1208 return response; 1209 } 1210 1211 /** 1212 * Parses the output from the body into the specified type and then wraps that in a {@link PojoRest}. 1213 * 1214 * <p> 1215 * Useful if you want to quickly retrieve a single value from inside of a larger JSON document. 1216 * 1217 * @param innerType The class type of the POJO being wrapped. 1218 * @return The parsed output wrapped in a {@link PojoRest}. 1219 * @throws RestCallException 1220 * <ul> 1221 * <li>If the input contains a syntax error or is malformed, or is not valid for the specified type. 1222 * <li>If a connection error occurred. 1223 * </ul> 1224 */ 1225 public PojoRest asPojoRest(Class<?> innerType) throws RestCallException { 1226 return new PojoRest(as(innerType)); 1227 } 1228 1229 /** 1230 * Same as {@link #asPojoRest(Class)} but sets the value in a mutable for fluent calls. 1231 * 1232 * @param m The mutable to set the value in. 1233 * @param innerType The class type of the POJO being wrapped. 1234 * @return The response object (for method chaining). 1235 * @throws RestCallException 1236 * <ul> 1237 * <li>If the input contains a syntax error or is malformed, or is not valid for the specified type. 1238 * <li>If a connection error occurred. 1239 * </ul> 1240 */ 1241 public RestResponse asPojoRest(Mutable<PojoRest> m, Class<?> innerType) throws RestCallException { 1242 m.set(asPojoRest(innerType)); 1243 return response; 1244 } 1245 1246 /** 1247 * Converts the output from the connection into an {@link OMap} and then wraps that in a {@link PojoRest}. 1248 * 1249 * <p> 1250 * Useful if you want to quickly retrieve a single value from inside of a larger JSON document. 1251 * 1252 * @return The parsed output wrapped in a {@link PojoRest}. 1253 * @throws RestCallException 1254 * <ul> 1255 * <li>If the input contains a syntax error or is malformed, or is not valid for the specified type. 1256 * <li>If a connection error occurred. 1257 * </ul> 1258 */ 1259 public PojoRest asPojoRest() throws RestCallException { 1260 return asPojoRest(OMap.class); 1261 } 1262 1263 /** 1264 * Same as {@link #asPojoRest()} but sets the value in a mutable for fluent calls. 1265 * 1266 * @param m The mutable to set the value in. 1267 * @return The response object (for method chaining). 1268 * @throws RestCallException 1269 * <ul> 1270 * <li>If the input contains a syntax error or is malformed, or is not valid for the specified type. 1271 * <li>If a connection error occurred. 1272 * </ul> 1273 */ 1274 public RestResponse asPojoRest(Mutable<PojoRest> m) throws RestCallException { 1275 m.set(asPojoRest()); 1276 return response; 1277 } 1278 1279 /** 1280 * Converts the contents of the response body to a string and then matches the specified pattern against it. 1281 * 1282 * <h5 class='section'>Example:</h5> 1283 * <p class='bcode w800'> 1284 * <jc>// Parse response using a regular expression.</jc> 1285 * Matcher <jv>matcher</jv> = <jv>client</jv> 1286 * .get(<jsf>URI</jsf>) 1287 * .run() 1288 * .getBody().asMatcher(Pattern.<jsm>compile</jsm>(<js>"foo=(.*)"</js>)); 1289 * 1290 * <jk>if</jk> (<jv>matcher</jv>.matches()) { 1291 * String <jv>foo</jv> = <jv>matcher</jv>.group(1); 1292 * } 1293 * </p> 1294 * 1295 * <ul class='notes'> 1296 * <li> 1297 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 1298 * <li> 1299 * This method automatically calls {@link #cache()} so that the body can be retrieved multiple times. 1300 * <li> 1301 * The input stream is automatically closed after this call. 1302 * </ul> 1303 * 1304 * @param pattern The regular expression pattern to match. 1305 * @return The matcher. 1306 * @throws RestCallException If a connection error occurred. 1307 */ 1308 public Matcher asMatcher(Pattern pattern) throws RestCallException { 1309 return pattern.matcher(asString()); 1310 } 1311 1312 /** 1313 * Same as {@link #asMatcher(Pattern)} but sets the value in a mutable for fluent calls. 1314 * 1315 * <h5 class='section'>Example:</h5> 1316 * <p class='bcode w800'> 1317 * <jc>// Parse response using a regular expression.</jc> 1318 * Mutable<Matcher> <jv>mutable</jv> = Mutable.<jsm>create</jsm>(); 1319 * 1320 * <jv>client</jv> 1321 * .get(<jsf>URI</jsf>) 1322 * .run() 1323 * .getBody().asMatcher(<jv>mutable</jv>, Pattern.<jsm>compile</jsm>(<js>"foo=(.*)"</js>)) 1324 * .assertStatus().is(200); 1325 * 1326 * <jk>if</jk> (<jv>matcher</jv>.get().matches()) { 1327 * String <jv>foo</jv> = <jv>matcher</jv>.get().group(1); 1328 * } 1329 * </p> 1330 * 1331 * 1332 * <ul class='notes'> 1333 * <li> 1334 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 1335 * <li> 1336 * This method automatically calls {@link #cache()} so that the body can be retrieved multiple times. 1337 * <li> 1338 * The input stream is automatically closed after this call. 1339 * </ul> 1340 * 1341 * @param m The mutable to set the value in. 1342 * @param pattern The regular expression pattern to match. 1343 * @return The response object (for method chaining). 1344 * @throws RestCallException If a connection error occurred. 1345 */ 1346 public RestResponse asMatcher(Mutable<Matcher> m, Pattern pattern) throws RestCallException { 1347 m.set(pattern.matcher(asString())); 1348 return response; 1349 } 1350 1351 /** 1352 * Converts the contents of the response body to a string and then matches the specified pattern against it. 1353 * 1354 * <h5 class='section'>Example:</h5> 1355 * <p class='bcode w800'> 1356 * <jc>// Parse response using a regular expression.</jc> 1357 * Matcher <jv>matcher</jv> = <jv>client</jv> 1358 * .get(<jsf>URI</jsf>) 1359 * .run() 1360 * .getBody().asMatcher(<js>"foo=(.*)"</js>); 1361 * 1362 * <jk>if</jk> (<jv>matcher</jv>.matches()) { 1363 * String <jv>foo</jv> = <jv>matcher</jv>.group(1); 1364 * } 1365 * </p> 1366 * 1367 * 1368 * <ul class='notes'> 1369 * <li> 1370 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 1371 * <li> 1372 * If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with 1373 * other methods that retrieve the content of the response. Otherwise a {@link RestCallException} 1374 * with an inner {@link IllegalStateException} will be thrown. 1375 * <li> 1376 * The input stream is automatically closed after this call. 1377 * </ul> 1378 * 1379 * @param regex The regular expression pattern to match. 1380 * @return The matcher. 1381 * @throws RestCallException If a connection error occurred. 1382 */ 1383 public Matcher asMatcher(String regex) throws RestCallException { 1384 return asMatcher(regex, 0); 1385 } 1386 1387 /** 1388 * Same as {@link #asMatcher(String)} but sets the value in a mutable for fluent calls. 1389 * 1390 * <h5 class='section'>Example:</h5> 1391 * <p class='bcode w800'> 1392 * <jc>// Parse response using a regular expression.</jc> 1393 * Mutable<Matcher> <jv>mutable</jv> = Mutable.<jsm>create</jsm>(); 1394 * 1395 * <jv>client</jv> 1396 * .get(<jsf>URI</jsf>) 1397 * .run() 1398 * .getBody().asMatcher(<jv>mutable</jv>, <js>"foo=(.*)"</js>) 1399 * .assertStatus().is(200); 1400 * 1401 * <jk>if</jk> (<jv>mutable</jv>.get().matches()) { 1402 * String <jv>foo</jv> = <jv>mutable</jv>.get().group(1); 1403 * } 1404 * 1405 * 1406 * <ul class='notes'> 1407 * <li> 1408 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 1409 * <li> 1410 * If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with 1411 * other methods that retrieve the content of the response. Otherwise a {@link RestCallException} 1412 * with an inner {@link IllegalStateException} will be thrown. 1413 * <li> 1414 * The input stream is automatically closed after this call. 1415 * </ul> 1416 * 1417 * @param m The mutable to set the value in. 1418 * @param regex The regular expression pattern to match. 1419 * @return The response object (for method chaining). 1420 * @throws RestCallException If a connection error occurred. 1421 */ 1422 public RestResponse asMatcher(Mutable<Matcher> m, String regex) throws RestCallException { 1423 asMatcher(m, regex, 0); 1424 return response; 1425 } 1426 1427 /** 1428 * Converts the contents of the response body to a string and then matches the specified pattern against it. 1429 * 1430 * <h5 class='section'>Example:</h5> 1431 * <p class='bcode w800'> 1432 * <jc>// Parse response using a regular expression.</jc> 1433 * Matcher <jv>matcher</jv> = <jv>client</jv> 1434 * .get(<jsf>URI</jsf>) 1435 * .run() 1436 * .getBody().asMatcher(<js>"foo=(.*)"</js>, <jsf>MULTILINE</jsf> & <jsf>CASE_INSENSITIVE</jsf>); 1437 * 1438 * <jk>if</jk> (<jv>matcher</jv>.matches()) { 1439 * String <jv>foo</jv> = <jv>matcher</jv>.group(1); 1440 * } 1441 * </p> 1442 * 1443 * 1444 * <ul class='notes'> 1445 * <li> 1446 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 1447 * <li> 1448 * If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with 1449 * other methods that retrieve the content of the response. Otherwise a {@link RestCallException} 1450 * with an inner {@link IllegalStateException} will be thrown. 1451 * <li> 1452 * The input stream is automatically closed after this call. 1453 * </ul> 1454 * 1455 * @param regex The regular expression pattern to match. 1456 * @param flags Pattern match flags. See {@link Pattern#compile(String, int)}. 1457 * @return The matcher. 1458 * @throws RestCallException If a connection error occurred. 1459 */ 1460 public Matcher asMatcher(String regex, int flags) throws RestCallException { 1461 return asMatcher(Pattern.compile(regex, flags)); 1462 } 1463 1464 /** 1465 * Same as {@link #asMatcher(String,int)} but sets the value in a mutable for fluent calls. 1466 * 1467 * <h5 class='section'>Example:</h5> 1468 * <p class='bcode w800'> 1469 * <jc>// Parse response using a regular expression.</jc> 1470 * Mutable<Matcher> <jv>mutable</jv> = Mutable.<jsm>create</jsm>(); 1471 * 1472 * <jv>client</jv> 1473 * .get(<jsf>URI</jsf>) 1474 * .run() 1475 * .getBody().asMatcher(<jv>mutable</jv>, <js>"foo=(.*)"</js>, <jsf>MULTILINE</jsf> & <jsf>CASE_INSENSITIVE</jsf>) 1476 * .assertStatus().is(200); 1477 * 1478 * <jk>if</jk> (<jv>mutable</jv>.get().matches()) { 1479 * String <jv>foo</jv> = <jv>mutable</jv>.get().group(1); 1480 * } 1481 * </p> 1482 * 1483 * 1484 * <ul class='notes'> 1485 * <li> 1486 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 1487 * <li> 1488 * If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with 1489 * other methods that retrieve the content of the response. Otherwise a {@link RestCallException} 1490 * with an inner {@link IllegalStateException} will be thrown. 1491 * <li> 1492 * The input stream is automatically closed after this call. 1493 * </ul> 1494 * 1495 * @param m The mutable to set the value in. 1496 * @param regex The regular expression pattern to match. 1497 * @param flags Pattern match flags. See {@link Pattern#compile(String, int)}. 1498 * @return The response object (for method chaining). 1499 * @throws RestCallException If a connection error occurred. 1500 */ 1501 public RestResponse asMatcher(Mutable<Matcher> m, String regex, int flags) throws RestCallException { 1502 asMatcher(m, Pattern.compile(regex, flags)); 1503 return response; 1504 } 1505 1506 /** 1507 * Returns the response that created this object. 1508 * 1509 * @return The response that created this object. 1510 */ 1511 public RestResponse toResponse() { 1512 return response; 1513 } 1514 1515 //------------------------------------------------------------------------------------------------------------------ 1516 // Assertions 1517 //------------------------------------------------------------------------------------------------------------------ 1518 1519 /** 1520 * Provides the ability to perform fluent-style assertions on this response body. 1521 * 1522 * <p> 1523 * This method is called directly from the {@link RestResponse#assertBody()} method to instantiate a fluent assertions object. 1524 * 1525 * <h5 class='section'>Examples:</h5> 1526 * <p class='bcode w800'> 1527 * <jc>// Validates the response body equals the text "OK".</jc> 1528 * <jv>client</jv> 1529 * .get(<jsf>URI</jsf>) 1530 * .run() 1531 * .assertBody().equals(<js>"OK"</js>); 1532 * 1533 * <jc>// Validates the response body contains the text "OK".</jc> 1534 * <jv>client</jv> 1535 * .get(<jsf>URI</jsf>) 1536 * .run() 1537 * .assertBody().contains(<js>"OK"</js>); 1538 * 1539 * <jc>// Validates the response body passes a predicate test.</jc> 1540 * <jv>client</jv> 1541 * .get(<jsf>URI</jsf>) 1542 * .run() 1543 * .assertBody().passes(<jv>x</jv> -> <jv>x</jv>.contains(<js>"OK"</js>)); 1544 * 1545 * <jc>// Validates the response body matches a regular expression.</jc> 1546 * <jv>client</jv> 1547 * .get(<jsf>URI</jsf>) 1548 * .run() 1549 * .assertBody().matches(<js>".*OK.*"</js>); 1550 * 1551 * <jc>// Validates the response body matches a regular expression using regex flags.</jc> 1552 * <jv>client</jv> 1553 * .get(<jsf>URI</jsf>) 1554 * .run() 1555 * .assertBody().matches(<js>".*OK.*"</js>, <jsf>MULTILINE</jsf> & <jsf>CASE_INSENSITIVE</jsf>); 1556 * 1557 * <jc>// Validates the response body matches a regular expression in the form of an existing Pattern.</jc> 1558 * Pattern <jv>p</jv> = Pattern.<jsm>compile</jsm>(<js>".*OK.*"</js>); 1559 * <jv>client</jv> 1560 * .get(<jsf>URI</jsf>) 1561 * .run() 1562 * .assertBody().matches(<jv>p</jv>); 1563 * </p> 1564 * 1565 * <p> 1566 * The assertion test returns the original response object allowing you to chain multiple requests like so: 1567 * <p class='bcode w800'> 1568 * <jc>// Validates the response body matches a regular expression.</jc> 1569 * MyBean <jv>bean</jv> = <jv>client</jv> 1570 * .get(<jsf>URI</jsf>) 1571 * .run() 1572 * .assertBody().matches(<js>".*OK.*"</js>); 1573 * .assertBody().doesNotMatch(<js>".*ERROR.*"</js>) 1574 * .getBody().as(MyBean.<jk>class</jk>); 1575 * </p> 1576 * 1577 * <ul class='notes'> 1578 * <li> 1579 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 1580 * <li> 1581 * This method automatically calls {@link #cache()} so that the body can be retrieved multiple times. 1582 * <li> 1583 * The input stream is automatically closed after this call. 1584 * </ul> 1585 * 1586 * @return A new fluent assertion object. 1587 * @throws RestCallException If REST call failed. 1588 */ 1589 public FluentStringAssertion<RestResponse> assertString() throws RestCallException { 1590 return new FluentStringAssertion<>(asString(), response); 1591 } 1592 1593 /** 1594 * Provides the ability to perform fluent-style assertions on the bytes of the response body. 1595 * 1596 * <p> 1597 * This method is called directly from the {@link RestResponse#assertBodyBytes()} method to instantiate a fluent assertions object. 1598 * 1599 * <h5 class='section'>Examples:</h5> 1600 * <p class='bcode w800'> 1601 * <jc>// Validates the response body equals the text "foo".</jc> 1602 * <jv>client</jv> 1603 * .get(<jsf>URI</jsf>) 1604 * .run() 1605 * .assertBodyBytes().hex().is(<js>"666F6F"</js>); 1606 * </p> 1607 * 1608 * <ul class='notes'> 1609 * <li> 1610 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 1611 * <li> 1612 * When using this method, the body is automatically cached by calling the {@link RestResponseBody#cache()}. 1613 * <li> 1614 * The input stream is automatically closed after this call. 1615 * </ul> 1616 * 1617 * @return A new fluent assertion object. 1618 * @throws RestCallException If REST call failed. 1619 */ 1620 public FluentByteArrayAssertion<RestResponse> assertBytes() throws RestCallException { 1621 return new FluentByteArrayAssertion<>(asBytes(), response); 1622 } 1623 1624 /** 1625 * Provides the ability to perform fluent-style assertions on this response body. 1626 * 1627 * <p> 1628 * This method is called directly from the {@link RestResponse#assertBody(Class)} method to instantiate a fluent assertions object. 1629 * 1630 * <p> 1631 * Converts the body of the response to the specified object using {@link #as(Class)} and returns it as a fluent assertions object. 1632 * 1633 * <h5 class='section'>Examples:</h5> 1634 * <p class='bcode w800'> 1635 * <jc>// Validates the response body bean is the expected value.</jc> 1636 * <jv>client</jv> 1637 * .get(<js>"/myBean"</js>) 1638 * .run() 1639 * .assertBody(MyBean.<jk>class</jk>).json().is(<js>"{foo:'bar'}"</js>); 1640 * </p> 1641 * 1642 * <ul class='notes'> 1643 * <li> 1644 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 1645 * <li> 1646 * If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with 1647 * other methods that retrieve the content of the response. Otherwise a {@link RestCallException} 1648 * with an inner {@link IllegalStateException} will be thrown. 1649 * <li> 1650 * The input stream is automatically closed after this call. 1651 * </ul> 1652 * 1653 * @param type The object type to create. 1654 * @return A new fluent assertion object. 1655 * @throws RestCallException If REST call failed. 1656 */ 1657 public FluentObjectAssertion<RestResponse> assertObject(Class<?> type) throws RestCallException { 1658 return new FluentObjectAssertion<>(as(type), response); 1659 } 1660 1661 //------------------------------------------------------------------------------------------------------------------ 1662 // HttpEntity passthrough methods. 1663 //------------------------------------------------------------------------------------------------------------------ 1664 1665 /** 1666 * Tells if the entity is capable of producing its data more than once. 1667 * 1668 * <p> 1669 * A repeatable entity's {@link #getContent()} and {@link #writeTo(OutputStream)} methods can be called more than 1670 * once whereas a non-repeatable entity's can not. 1671 * 1672 * <ul class='notes'> 1673 * <li>This method always returns <jk>true</jk> if the response body is cached (see {@link #cache()}). 1674 * </ul> 1675 * 1676 * @return <jk>true</jk> if the entity is repeatable, <jk>false</jk> otherwise. 1677 */ 1678 @Override /* HttpEntity */ 1679 public boolean isRepeatable() { 1680 return cached || entity.isRepeatable(); 1681 } 1682 1683 /** 1684 * Tells about chunked encoding for this entity. 1685 * 1686 * <p> 1687 * The primary purpose of this method is to indicate whether chunked encoding should be used when the entity is sent. 1688 * <br>For entities that are received, it can also indicate whether the entity was received with chunked encoding. 1689 * 1690 * <p> 1691 * The behavior of wrapping entities is implementation dependent, but should respect the primary purpose. 1692 * 1693 * @return <jk>true</jk> if chunked encoding is preferred for this entity, or <jk>false</jk> if it is not. 1694 */ 1695 @Override /* HttpEntity */ 1696 public boolean isChunked() { 1697 return entity.isChunked(); 1698 } 1699 1700 /** 1701 * Tells the length of the content, if known. 1702 * 1703 * @return 1704 * The number of bytes of the content, or a negative number if unknown. 1705 * <br>If the content length is known but exceeds {@link Long#MAX_VALUE}, a negative number is returned. 1706 */ 1707 @Override /* HttpEntity */ 1708 public long getContentLength() { 1709 return cache != null ? cache.length : entity.getContentLength(); 1710 } 1711 1712 /** 1713 * Obtains the <c>Content-Type</c> header, if known. 1714 * 1715 * <p> 1716 * This is the header that should be used when sending the entity, or the one that was received with the entity. 1717 * It can include a charset attribute. 1718 * 1719 * @return The <c>Content-Type</c> header for this entity, or <jk>null</jk> if the content type is unknown. 1720 */ 1721 @Override /* HttpEntity */ 1722 public RestResponseHeader getContentType() { 1723 return new RestResponseHeader(request, response, entity.getContentType()); 1724 } 1725 1726 /** 1727 * Obtains the Content-Encoding header, if known. 1728 * 1729 * <p> 1730 * This is the header that should be used when sending the entity, or the one that was received with the entity. 1731 * <br>Wrapping entities that modify the content encoding should adjust this header accordingly. 1732 * 1733 * @return The <c>Content-Encoding</c> header for this entity, or <jk>null</jk> if the content encoding is unknown. 1734 */ 1735 @Override /* HttpEntity */ 1736 public RestResponseHeader getContentEncoding() { 1737 return new RestResponseHeader(request, response, entity.getContentEncoding()); 1738 } 1739 1740 /** 1741 * Returns a content stream of the entity. 1742 * 1743 * <ul class='notes'> 1744 * <li>This method is equivalent to {@link #asInputStream()} which is the preferred method for fluent-style coding. 1745 * <li>This input stream will auto-close once the end of stream has been reached. 1746 * <li>It is up to the caller to properly close this stream if not fully consumed. 1747 * <li>This method can be called multiple times if the entity is repeatable or the cache flag is set on this object. 1748 * <li>Calling this method multiple times on a non-repeatable or cached body will throw a {@link IllegalStateException}. 1749 * Note that this is different from the HttpClient specs for this method. 1750 * </ul> 1751 * 1752 * @return Content stream of the entity. 1753 */ 1754 @Override /* HttpEntity */ 1755 public InputStream getContent() throws IOException, UnsupportedOperationException { 1756 return asInputStream(); 1757 } 1758 1759 /** 1760 * Writes the entity content out to the output stream. 1761 * 1762 * <ul class='notes'> 1763 * <li>This method is equivalent to {@link #pipeTo(OutputStream)} which is the preferred method for fluent-style coding. 1764 * </ul> 1765 * 1766 * @param outstream The output stream to write entity content to. 1767 */ 1768 @Override /* HttpEntity */ 1769 public void writeTo(OutputStream outstream) throws IOException { 1770 pipeTo(outstream); 1771 } 1772 1773 /** 1774 * Tells whether this entity depends on an underlying stream. 1775 * 1776 * <ul class='notes'> 1777 * <li>This method always returns <jk>false</jk> if the response body is cached (see {@link #cache()}. 1778 * </ul> 1779 * 1780 * @return <jk>true</jk> if the entity content is streamed, <jk>false</jk> otherwise. 1781 */ 1782 @Override /* HttpEntity */ 1783 public boolean isStreaming() { 1784 return cached ? false : entity.isStreaming(); 1785 } 1786 1787 /** 1788 * This method is called to indicate that the content of this entity is no longer required. 1789 * 1790 * <p> 1791 * This method is of particular importance for entities being received from a connection. 1792 * <br>The entity needs to be consumed completely in order to re-use the connection with keep-alive. 1793 * 1794 * @throws IOException If an I/O error occurs. 1795 * @deprecated Use standard java convention to ensure resource deallocation by calling {@link InputStream#close()} on 1796 * the input stream returned by {@link #getContent()} 1797 */ 1798 @Override /* HttpEntity */ 1799 @Deprecated 1800 public void consumeContent() throws IOException { 1801 entity.consumeContent(); 1802 } 1803 1804 //------------------------------------------------------------------------------------------------------------------ 1805 // Utility methods 1806 //------------------------------------------------------------------------------------------------------------------ 1807 1808 private BeanContext getBeanContext() { 1809 return parser == null ? BeanContext.DEFAULT : parser; 1810 } 1811 1812 private <T> ClassMeta<T> getClassMeta(Class<T> c) { 1813 return getBeanContext().getClassMeta(c); 1814 } 1815 1816 private <T> ClassMeta<T> getClassMeta(Type type, Type...args) { 1817 return getBeanContext().getClassMeta(type, args); 1818 } 1819}