001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.rest.client; 018 019import static java.lang.Character.*; 020import static java.util.logging.Level.*; 021import static org.apache.juneau.collections.JsonMap.*; 022import static org.apache.juneau.common.utils.ThrowableUtils.*; 023import static org.apache.juneau.common.utils.Utils.*; 024import static org.apache.juneau.http.HttpEntities.*; 025import static org.apache.juneau.http.HttpHeaders.*; 026import static org.apache.juneau.http.HttpMethod.*; 027import static org.apache.juneau.http.HttpParts.*; 028import static org.apache.juneau.httppart.HttpPartType.*; 029import static org.apache.juneau.internal.StateMachineState.*; 030import static org.apache.juneau.rest.client.RestOperation.*; 031 032import java.io.*; 033import java.lang.annotation.Annotation; 034import java.lang.reflect.*; 035import java.lang.reflect.Proxy; 036import java.net.*; 037import java.nio.charset.*; 038import java.text.*; 039import java.util.*; 040import java.util.concurrent.*; 041import java.util.function.*; 042import java.util.logging.*; 043import java.util.regex.*; 044 045import javax.net.ssl.*; 046 047import org.apache.http.*; 048import org.apache.http.auth.*; 049import org.apache.http.client.*; 050import org.apache.http.client.CookieStore; 051import org.apache.http.client.config.*; 052import org.apache.http.client.entity.*; 053import org.apache.http.client.methods.*; 054import org.apache.http.client.utils.*; 055import org.apache.http.config.*; 056import org.apache.http.conn.*; 057import org.apache.http.conn.routing.*; 058import org.apache.http.conn.socket.*; 059import org.apache.http.conn.util.*; 060import org.apache.http.cookie.*; 061import org.apache.http.impl.client.*; 062import org.apache.http.impl.conn.*; 063import org.apache.http.params.*; 064import org.apache.http.protocol.*; 065import org.apache.juneau.*; 066import org.apache.juneau.annotation.*; 067import org.apache.juneau.collections.*; 068import org.apache.juneau.common.utils.*; 069import org.apache.juneau.cp.*; 070import org.apache.juneau.html.*; 071import org.apache.juneau.http.entity.*; 072import org.apache.juneau.http.header.*; 073import org.apache.juneau.http.part.*; 074import org.apache.juneau.http.remote.*; 075import org.apache.juneau.http.resource.*; 076import org.apache.juneau.httppart.*; 077import org.apache.juneau.httppart.bean.*; 078import org.apache.juneau.internal.*; 079import org.apache.juneau.json.*; 080import org.apache.juneau.marshaller.*; 081import org.apache.juneau.msgpack.*; 082import org.apache.juneau.oapi.*; 083import org.apache.juneau.objecttools.*; 084import org.apache.juneau.parser.*; 085import org.apache.juneau.parser.ParseException; 086import org.apache.juneau.plaintext.*; 087import org.apache.juneau.reflect.*; 088import org.apache.juneau.rest.client.assertion.*; 089import org.apache.juneau.rest.client.remote.*; 090import org.apache.juneau.serializer.*; 091import org.apache.juneau.uon.*; 092import org.apache.juneau.urlencoding.*; 093import org.apache.juneau.utils.*; 094import org.apache.juneau.xml.*; 095 096/** 097 * Utility class for interfacing with remote REST interfaces. 098 * 099 * <p> 100 * Built upon the feature-rich Apache HttpClient library, the Juneau RestClient API adds support for fluent-style 101 * REST calls and the ability to perform marshalling of POJOs to and from HTTP parts. 102 * 103 * <h5 class='figure'>Example:</h5> 104 * <p class='bjava'> 105 * <jc>// Create a basic REST client with JSON support and download a bean.</jc> 106 * MyBean <jv>bean</jv> = RestClient.<jsm>create</jsm>() 107 * .json5() 108 * .build() 109 * .get(<jsf>URI</jsf>) 110 * .run() 111 * .assertStatus().asCode().is(200) 112 * .assertHeader(<js>"Content-Type"</js>).matchesSimple(<js>"application/json*"</js>) 113 * .getContent().as(MyBean.<jk>class</jk>); 114 * </p> 115 * 116 * <p> 117 * Breaking apart the fluent call, we can see the classes being used: 118 * <p class='bjava'> 119 * RestClient.Builder <jv>builder</jv> = RestClient.<jsm>create</jsm>().json5(); 120 * RestClient <jv>client</jv> = <jv>builder</jv>.build(); 121 * RestRequest <jv>req</jv> = <jv>client</jv>.get(<jsf>URI</jsf>); 122 * RestResponse <jv>res</jv> = <jv>req</jv>.run(); 123 * RestResponseStatusLineAssertion <jv>statusLineAssertion</jv> = <jv>res</jv>.assertStatus(); 124 * FluentIntegerAssertion<RestResponse> <jv>codeAssertion</jv> = <jv>statusLineAssertion</jv>.asCode(); 125 * <jv>res</jv> = <jv>codeAssertion</jv>.is(200); 126 * FluentStringAssertion<RestResponse> <jv>headerAssertion</jv> = <jv>res</jv>.assertHeader(<js>"Content-Type"</js>); 127 * <jv>res</jv> = <jv>headerAssertion</jv>.matchesSimple(<js>"application/json*"</js>); 128 * RestResponseBody <jv>content</jv> = <jv>res</jv>.getContent(); 129 * MyBean <jv>bean</jv> = <jv>content</jv>.as(MyBean.<jk>class</jk>); 130 * </p> 131 * 132 * <p> 133 * It additionally provides support for creating remote proxy interfaces using REST as the transport medium. 134 * 135 * <h5 class='figure'>Example:</h5> 136 * <p class='bjava'> 137 * <jc>// Define a Remote proxy for interacting with a REST interface.</jc> 138 * <ja>@Remote</ja>(path=<js>"/petstore"</js>) 139 * <jk>public interface</jk> PetStore { 140 * 141 * <ja>@RemotePost</ja>(<js>"/pets"</js>) 142 * Pet addPet( 143 * <ja>@Content</ja> CreatePet <jv>pet</jv>, 144 * <ja>@Header</ja>(<js>"E-Tag"</js>) UUID <jv>etag</jv>, 145 * <ja>@Query</ja>(<js>"debug"</js>) <jk>boolean</jk> <jv>debug</jv> 146 * ); 147 * } 148 * 149 * <jc>// Use a RestClient with default JSON 5 support.</jc> 150 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().json5().build(); 151 * 152 * PetStore <jv>store</jv> = <jv>client</jv>.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>); 153 * CreatePet <jv>createPet</jv> = <jk>new</jk> CreatePet(<js>"Fluffy"</js>, 9.99); 154 * Pet <jv>pet</jv> = <jv>store</jv>.addPet(<jv>createPet</jv>, UUID.<jsm>randomUUID</jsm>(), <jk>true</jk>); 155 * </p> 156 * 157 * <p> 158 * The classes are closely tied to Apache HttpClient, yet provide lots of additional functionality: 159 * <ul class='javatree'> 160 * <li class='jc'>{@link RestClient} <jk>extends</jk> {@link HttpClient}, creates {@link RestRequest} objects. 161 * <li class='jc'>{@link RestRequest} <jk>extends</jk> {@link HttpUriRequest}, creates {@link RestResponse} objects. 162 * <li class='jc'>{@link RestResponse} creates {@link ResponseContent} and {@link ResponseHeader} objects. 163 * <li class='jc'>{@link ResponseContent} <jk>extends</jk> {@link HttpEntity} 164 * <li class='jc'>{@link ResponseHeader} <jk>extends</jk> {@link Header} 165 * </ul> 166 * 167 * 168 * <p> 169 * Instances of this class are built using the {@link Builder} class which can be constructed using 170 * the {@link #create() RestClient.create()} method as shown above. 171 * 172 * <p> 173 * Clients are typically created with a root URI so that relative URIs can be used when making requests. 174 * This is done using the {@link Builder#rootUrl(Object)} method. 175 * 176 * <h5 class='figure'>Example:</h5> 177 * <p class='bjava'> 178 * <jc>// Create a client where all URIs are relative to localhost.</jc> 179 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().json().rootUrl(<js>"http://localhost:5000"</js>).build(); 180 * 181 * <jc>// Use relative paths.</jc> 182 * String <jv>body</jv> = <jv>client</jv>.get(<js>"/subpath"</js>).run().getContent().asString(); 183 * </p> 184 * 185 * <p> 186 * The {@link RestClient} class creates {@link RestRequest} objects using the following methods: 187 * 188 * <ul class='javatree'> 189 * <li class='jc'>{@link RestClient} 190 * <ul> 191 * <li class='jm'>{@link RestClient#get(Object) get(uri)} / {@link RestClient#get() get()} 192 * <li class='jm'>{@link RestClient#put(Object,Object) put(uri,body)} / {@link RestClient#put(Object) put(uri)} 193 * <li class='jm'>{@link RestClient#post(Object) post(uri,body)} / {@link RestClient#post(Object) post(uri)} 194 * <li class='jm'>{@link RestClient#patch(Object,Object) patch(uri,body)} / {@link RestClient#patch(Object) patch(uri)} 195 * <li class='jm'>{@link RestClient#delete(Object) delete(uri)} 196 * <li class='jm'>{@link RestClient#head(Object) head(uri)} 197 * <li class='jm'>{@link RestClient#options(Object) options(uri)} 198 * <li class='jm'>{@link RestClient#formPost(Object,Object) formPost(uri,body)} / {@link RestClient#formPost(Object) formPost(uri)} 199 * <li class='jm'>{@link RestClient#formPostPairs(Object,String...) formPostPairs(uri,parameters...)} 200 * <li class='jm'>{@link RestClient#request(String,Object,Object) request(method,uri,body)} 201 * </ul> 202 * </ul> 203 * 204 * <p> 205 * The {@link RestRequest} class creates {@link RestResponse} objects using the following methods: 206 * 207 * <ul class='javatree'> 208 * <li class='jc'>{@link RestRequest} 209 * <ul> 210 * <li class='jm'>{@link RestRequest#run() run()} 211 * <li class='jm'>{@link RestRequest#complete() complete()} 212 * </ul> 213 * </ul> 214 * 215 * <p> 216 * The distinction between the two methods is that {@link RestRequest#complete() complete()} automatically consumes the response body and 217 * {@link RestRequest#run() run()} does not. Note that you must consume response bodies in order for HTTP connections to be freed up 218 * for reuse! The {@link InputStream InputStreams} returned by the {@link ResponseContent} object are auto-closing once 219 * they are exhausted, so it is often not necessary to explicitly close them. 220 * 221 * <p> 222 * The following examples show the distinction between the two calls: 223 * 224 * <p class='bjava'> 225 * <jc>// Consuming the response, so use run().</jc> 226 * String <jv>body</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getContent().asString(); 227 * 228 * <jc>// Only interested in response status code, so use complete().</jc> 229 * <jk>int</jk> <jv>status</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).complete().getStatusCode(); 230 * </p> 231 * 232 * 233 * <h4 class='topic'>POJO Marshalling</h4> 234 * 235 * <p> 236 * By default, JSON support is provided for HTTP request and response bodies. 237 * Other languages can be specified using any of the following builder methods: 238 * <ul class='javatree'> 239 * <li class='jc'>{@link Builder} 240 * <ul> 241 * <li class='jm'>{@link Builder#json() json()} 242 * <li class='jm'>{@link Builder#json5() json5()} 243 * <li class='jm'>{@link Builder#xml() xml()} 244 * <li class='jm'>{@link Builder#html() html()} 245 * <li class='jm'>{@link Builder#plainText() plainText()} 246 * <li class='jm'>{@link Builder#msgPack() msgPack()} 247 * <li class='jm'>{@link Builder#uon() uon()} 248 * <li class='jm'>{@link Builder#urlEnc() urlEnc()} 249 * <li class='jm'>{@link Builder#openApi() openApi()} 250 * </ul> 251 * </ul> 252 * 253 * <h5 class='figure'>Example:</h5> 254 * <p class='bjava'> 255 * <jc>// Create a basic REST client with JSON 5 support.</jc> 256 * <jc>// Typically easier to use when performing unit tests.</jc> 257 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().json5().build(); 258 * </p> 259 * 260 * <p> 261 * Clients can also support multiple languages: 262 * 263 * <h5 class='figure'>Example:</h5> 264 * <p class='bjava'> 265 * <jc>// Create a REST client with support for multiple languages.</jc> 266 * RestClient <jv>client1</jv> = RestClient.<jsm>create</jsm>().json().xml().openApi().build(); 267 * 268 * <jc>// Create a REST client with support for all supported languages.</jc> 269 * RestClient <jv>client2</jv> = RestClient.<jsm>create</jsm>().universal().build(); 270 * </p> 271 * 272 * <p> 273 * When using clients with multiple language support, you must specify the <c>Content-Type</c> header on requests 274 * with bodies to specify which serializer should be selected. 275 * 276 * <p class='bjava'> 277 * <jc>// Create a REST client with support for multiple languages.</jc> 278 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().universal().build(); 279 * 280 * <jv>client</jv> 281 * .post(<jsf>URI</jsf>, <jv>myBean</jv>) 282 * .contentType(<js>"application/json"</js>) 283 * .complete() 284 * .assertStatus().is(200); 285 * </p> 286 * 287 * <p> 288 * Languages can also be specified per-request. 289 * 290 * <p class='bjava'> 291 * <jc>// Create a REST client with no default languages supported.</jc> 292 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().build(); 293 * 294 * <jc>// Use JSON for this request.</jc> 295 * <jv>client</jv> 296 * .post(<jsf>URI</jsf>, <jv>myBean</jv>) 297 * .json() 298 * .complete() 299 * .assertStatus().is(200); 300 * </p> 301 * 302 * 303 * <p> 304 * The {@link Builder} class provides convenience methods for setting common serializer and parser 305 * settings. 306 * 307 * <h5 class='figure'>Example:</h5> 308 * <p class='bjava'> 309 * <jc>// Create a basic REST client with JSON support.</jc> 310 * <jc>// Use single-quotes and whitespace.</jc> 311 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().json().sq().ws().build(); 312 * </p> 313 * 314 * <p> 315 * Other methods are also provided for specifying the serializers and parsers used for lower-level marshalling support: 316 * <ul class='javatree'> 317 * <li class='jc'>{@link Builder} 318 * <ul> 319 * <li class='jm'>{@link Builder#serializer(Serializer) serializer(Serializer)} 320 * <li class='jm'>{@link Builder#parser(Parser) parser(Parser)} 321 * <li class='jm'>{@link Builder#marshaller(Marshaller) marshaller(Marshaller)} 322 * </ul> 323 * </ul> 324 * 325 * <p> 326 * HTTP parts (headers, query parameters, form data...) are serialized and parsed using the {@link HttpPartSerializer} 327 * and {@link HttpPartParser} APIs. By default, clients are configured to use {@link OpenApiSerializer} and 328 * {@link OpenApiParser}. These can be overridden using the following methods: 329 * <ul class='javatree'> 330 * <li class='jc'>{@link Builder} 331 * <ul> 332 * <li class='jm'>{@link Builder#partSerializer(Class) partSerializer(Class<? extends HttpPartSerializer>)} 333 * <li class='jm'>{@link Builder#partParser(Class) partParser(Class<? extends HttpPartParser>)} 334 * </ul> 335 * </ul> 336 * 337 * 338 * <h4 class='topic'>Request Headers</h4> 339 * <p> 340 * Per-client or per-request headers can be specified using the following methods: 341 * <ul class='javatree'> 342 * <li class='jc'>{@link Builder} 343 * <ul> 344 * <li class='jm'>{@link Builder#headers() headerData()} 345 * <li class='jm'>{@link Builder#header(String,String) header(String,Object)} 346 * <li class='jm'>{@link Builder#header(String,Supplier) header(String,Supplier<?>)} 347 * <li class='jm'>{@link Builder#headers(Header...) headers(Header...)} 348 * <li class='jm'>{@link Builder#headersDefault(Header...) defaultHeaders(Header...)} 349 * </ul> 350 * <li class='jc'>{@link RestRequest} 351 * <ul> 352 * <li class='jm'>{@link RestRequest#header(String,Object) header(String,Object)} 353 * <li class='jm'>{@link RestRequest#headers(Header...) headers(Header...)} 354 * <li class='jm'>{@link RestRequest#headersBean(Object) headersBean(Object)} 355 * <li class='jm'>{@link RestRequest#headerPairs(String...) headerPairs(String...)} 356 * </ul> 357 * </ul> 358 * 359 * <p> 360 * The supplier methods are particularly useful for header values whose values may change over time (such as <c>Authorization</c> headers 361 * which may need to change every few minutes). 362 * </p> 363 * 364 * <h5 class='figure'>Example:</h5> 365 * <p class='bjava'> 366 * <jc>// Create a client that adds a dynamic Authorization header to every request.</jc> 367 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().header(<js>"Authorization"</js>, ()->getMyAuthToken()).build(); 368 * </p> 369 * 370 * <p> 371 * The {@link HttpPartSchema} API allows you to define OpenAPI schemas to POJO data structures on both requests 372 * and responses. 373 * 374 * <h5 class='figure'>Example:</h5> 375 * <p class='bjava'> 376 * <jc>// Create a client that adds a header "Foo: bar|baz" to every request.</jc> 377 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>() 378 * .header(<js>"Foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), <jsf>T_ARRAY_PIPES</jsf>) 379 * .build(); 380 * </p> 381 * 382 * <p> 383 * The methods with {@link ListOperation} parameters allow you to control whether new headers get appended, prepended, or 384 * replace existing headers with the same name. 385 * 386 * <h5 class='section'>Notes:</h5><ul> 387 * <li class='note'>Methods that pass in POJOs convert values to strings using the part serializers. Methods that pass in <c>Header</c> or 388 * <c>NameValuePair</c> objects use the values returned by that bean directly. 389 * </ul> 390 * 391 * 392 * <h4 class='topic'>Request Query Parameters</h4> 393 * <p> 394 * Per-client or per-request query parameters can be specified using the following methods: 395 * <ul class='javatree'> 396 * <li class='jc'>{@link Builder} 397 * <ul> 398 * <li class='jm'>{@link Builder#queryData() queryData()} 399 * <li class='jm'>{@link Builder#queryData(String,String) queryData(String,String)} 400 * <li class='jm'>{@link Builder#queryData(String,Supplier) queryData(String,Supplier<?>)} 401 * <li class='jm'>{@link Builder#queryData(NameValuePair...) queryData(NameValuePair...)} 402 * <li class='jm'>{@link Builder#queryDataDefault(NameValuePair...) defaultQueryData(NameValuePair...)} 403 * </ul> 404 * <li class='jc'>{@link RestRequest} 405 * <ul> 406 * <li class='jm'>{@link RestRequest#queryData(String,Object) queryData(String,Object)} 407 * <li class='jm'>{@link RestRequest#queryData(NameValuePair...) queryData(NameValuePair...)} 408 * <li class='jm'>{@link RestRequest#queryDataBean(Object) queryDataBean(Object)} 409 * <li class='jm'>{@link RestRequest#queryCustom(Object) queryCustom(Object)} 410 * <li class='jm'>{@link RestRequest#queryDataPairs(String...) queryDataPairs(String...)} 411 * </ul> 412 * </ul> 413 * 414 * <h5 class='figure'>Example:</h5> 415 * <p class='bjava'> 416 * <jc>// Create a client that adds a ?foo=bar query parameter to every request.</jc> 417 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().query(<js>"foo"</js>, <js>"bar"</js>).build(); 418 * 419 * <jc>// Or do it on every request.</jc> 420 * String <jv>response</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).query(<js>"foo"</js>, <js>"bar"</js>).run().getContent().asString(); 421 * </p> 422 * 423 * <h5 class='section'>Notes:</h5><ul> 424 * <li class='note'>Like header values, dynamic values and OpenAPI schemas are supported. 425 * <li class='note'>Methods that pass in POJOs convert values to strings using the part serializers. Methods that pass in <c>NameValuePair</c> 426 * objects use the values returned by that bean directly. 427 * </ul> 428 * 429 * 430 * <h4 class='topic'>Request Form Data</h4> 431 * 432 * <p> 433 * Per-client or per-request form-data parameters can be specified using the following methods: 434 * <ul class='javatree'> 435 * <li class='jc'>{@link Builder} 436 * <ul> 437 * <li class='jm'>{@link Builder#formData() formData()} 438 * <li class='jm'>{@link Builder#formData(String,String) formData(String,String)} 439 * <li class='jm'>{@link Builder#formData(String,Supplier) formData(String,Supplier<?>)} 440 * <li class='jm'>{@link Builder#formData(NameValuePair...) formDatas(NameValuePair...)} 441 * <li class='jm'>{@link Builder#formDataDefault(NameValuePair...) defaultFormData(NameValuePair...)} 442 * </ul> 443 * <li class='jc'>{@link RestRequest} 444 * <ul> 445 * <li class='jm'>{@link RestRequest#formData(String,Object) formData(String,Object)} 446 * <li class='jm'>{@link RestRequest#formData(NameValuePair...) formData(NameValuePair...)} 447 * <li class='jm'>{@link RestRequest#formDataBean(Object) formDataBean(Object)} 448 * <li class='jm'>{@link RestRequest#formDataCustom(Object) formDataCustom(Object)} 449 * <li class='jm'>{@link RestRequest#formDataPairs(String...) formDataPairs(String...)} 450 * </ul> 451 * </ul> 452 * 453 * <h5 class='section'>Notes:</h5><ul> 454 * <li class='note'>Like header values, dynamic values and OpenAPI schemas are supported. 455 * <li class='note'>Methods that pass in POJOs convert values to strings using the part serializers. Methods that pass in <c>NameValuePair</c> 456 * objects use the values returned by that bean directly. 457 * </ul> 458 * 459 * 460 * <h4 class='topic'>Request Body</h4> 461 * 462 * <p> 463 * The request body can either be passed in with the client creator method (e.g. {@link RestClient#post(Object,Object) post(uri,body)}), 464 * or can be specified via the following methods: 465 * 466 * <ul class='javatree'> 467 * <li class='jc'>{@link RestRequest} 468 * <ul> 469 * <li class='jm'>{@link RestRequest#content(Object) body(Object)} 470 * <li class='jm'>{@link RestRequest#content(Object,HttpPartSchema) body(Object,HttpPartSchema)} 471 * </ul> 472 * </ul> 473 * 474 * <p> 475 * The request body can be any of the following types: 476 * <ul class='javatree'> 477 * <li class='jc'> 478 * {@link Object} - POJO to be converted to text using the {@link Serializer} defined on the client or request. 479 * <li class='jc'> 480 * {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource. 481 * <li class='jc'> 482 * {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource. 483 * <li class='jc'> 484 * {@link HttpResource} - Raw contents will be serialized to remote resource. Additional headers and media type will be set on request. 485 * <li class='jc'> 486 * {@link HttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient. 487 * <li class='jc'> 488 * {@link PartList} - Converted to a URL-encoded FORM post. 489 * <li class='jc'> 490 * {@link Supplier} - A supplier of anything on this list. 491 * </ul> 492 * 493 * <h5 class='section'>Notes:</h5><ul> 494 * <li class='note'>If the serializer on the client or request is explicitly set to <jk>null</jk>, POJOs will be converted to strings 495 * using the registered part serializer as content type <js>"text/plain</js>. If the part serializer is also <jk>null</jk>, 496 * POJOs will be converted to strings using {@link ClassMeta#toString(Object)} which typically just calls {@link Object#toString()}. 497 * </ul> 498 * 499 * 500 * <h4 class='topic'>Response Status</h4> 501 * 502 * <p> 503 * After execution using {@link RestRequest#run()} or {@link RestRequest#complete()}, the following methods can be used 504 * to get the response status: 505 * 506 * <ul class='javatree'> 507 * <li class='jc'>{@link RestResponse} 508 * <ul> 509 * <li class='jm'><c>{@link RestResponse#getStatusLine() getStatusLine()} <jk>returns</jk> {@link StatusLine}</c> 510 * <li class='jm'><c>{@link RestResponse#getStatusCode() getStatusCode()} <jk>returns</jk> <jk>int</jk></c> 511 * <li class='jm'><c>{@link RestResponse#getReasonPhrase() getReasonPhrase()} <jk>returns</jk> String</c> 512 * <li class='jm'><c>{@link RestResponse#assertStatus() assertStatus()} <jk>returns</jk> {@link FluentResponseStatusLineAssertion}</c> 513 * </ul> 514 * </ul> 515 * 516 * <h5 class='figure'>Example:</h5> 517 * <p class='bjava'> 518 * <jc>// Only interested in status code.</jc> 519 * <jk>int</jk> <jv>statusCode</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).complete().getStatusCode(); 520 * </p> 521 * 522 * <p> 523 * Equivalent methods with mutable parameters are provided to allow access to status values without breaking fluent call chains. 524 * 525 * <h5 class='figure'>Example:</h5> 526 * <p class='bjava'> 527 * <jc>// Interested in multiple values.</jc> 528 * Value<Integer> <jv>statusCode</jv> = Value.<jsm>create</jsm>(); 529 * Value<String> <jv>reasonPhrase</jv> = Value.<jsm>create</jsm>(); 530 * 531 * <jv>client</jv>.get(<jsf>URI</jsf>).complete().getStatusCode(<jv>statusCode</jv>).getReasonPhrase(<jv>reasonPhrase</jv>); 532 * System.<jsf>err</jsf>.println(<js>"statusCode="</js>+<jv>statusCode</jv>.get()+<js>", reasonPhrase="</js>+<jv>reasonPhrase</jv>.get()); 533 * </p> 534 * 535 * <h5 class='section'>Notes:</h5><ul> 536 * <li class='note'>If you are only interested in the response status and not the response body, be sure to use {@link RestRequest#complete()} instead 537 * of {@link RestRequest#run()} to make sure the response body gets automatically cleaned up. Otherwise you must 538 * consume the response yourself. 539 * </ul> 540 * 541 * <p> 542 * The assertion method is provided for quickly asserting status codes in fluent calls. 543 * 544 * <h5 class='figure'>Example:</h5> 545 * <p class='bjava'> 546 * <jc>// Status assertion using a static value.</jc> 547 * String <jv>body</jv> = <jv>client</jv>.get(<jsf>URI</jsf>) 548 * .run() 549 * .assertStatus().asCode().isBetween(200,399) 550 * .getContent().asString(); 551 * 552 * <jc>// Status assertion using a predicate.</jc> 553 * String <jv>body</jv> = <jv>client</jv>.get(<jsf>URI</jsf>) 554 * .run() 555 * .assertStatus().asCode().is(<jv>x</jv> -> <jv>x</jv><400) 556 * .getContent().asString(); 557 * </p> 558 * 559 * 560 * <h4 class='topic'>Response Headers</h4> 561 * 562 * <p> 563 * Response headers are accessed through the following methods: 564 * 565 * <ul class='javatree'> 566 * <li class='jc'>{@link RestResponse} 567 * <ul> 568 * <li class='jm'><c>{@link RestResponse#getHeaders(String) getHeaders(String)} <jk>returns</jk> {@link ResponseHeader}[]</c> 569 * <li class='jm'><c>{@link RestResponse#getFirstHeader(String) getFirstHeader(String)} <jk>returns</jk> {@link ResponseHeader}</c> 570 * <li class='jm'><c>{@link RestResponse#getLastHeader(String) getLastHeader(String)} <jk>returns</jk> {@link ResponseHeader}</c> 571 * <li class='jm'><c>{@link RestResponse#getAllHeaders() getAllHeaders()} <jk>returns</jk> {@link ResponseHeader}[]</c> 572 * <li class='jm'><c>{@link RestResponse#getStringHeader(String) getStringHeader(String)} <jk>returns</jk> String</c> 573 * <li class='jm'><c>{@link RestResponse#containsHeader(String) containsHeader(String)} <jk>returns</jk> <jk>boolean</jk></c> 574 * </ul> 575 * </ul> 576 * 577 * <p> 578 * The {@link RestResponse#getFirstHeader(String)} and {@link RestResponse#getLastHeader(String)} methods return an empty {@link ResponseHeader} object instead of<jk>null</jk>. 579 * This allows it to be used more easily in fluent calls. 580 * 581 * <h5 class='figure'>Example:</h5> 582 * <p class='bjava'> 583 * <jc>// See if response contains Location header.</jc> 584 * <jk>boolean</jk> <jv>hasLocationHeader</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).complete().getLastHeader(<js>"Location"</js>).exists(); 585 * </p> 586 * 587 * <p> 588 * The {@link ResponseHeader} class extends from the HttpClient {@link Header} class and provides several convenience 589 * methods: 590 * 591 * <ul class='javatree'> 592 * <li class='jc'>{@link ResponseHeader} 593 * <ul> 594 * <li class='jm'><c>{@link ResponseHeader#isPresent() isPresent()} <jk>returns</jk> <jk>boolean</jk></c> 595 * <li class='jm'><c>{@link ResponseHeader#asString() asString()} <jk>returns</jk> String</c> 596 * <li class='jm'><c>{@link ResponseHeader#as(Type,Type...) as(Type,Type...)} <jk>returns</jk> T</c> 597 * <li class='jm'><c>{@link ResponseHeader#as(Class) as(Class<T>)} <jk>returns</jk> T</c> 598 * <li class='jm'><c>{@link ResponseHeader#asMatcher(Pattern) asMatcher(Pattern)} <jk>returns</jk> {@link Matcher}</c> 599 * <li class='jm'><c>{@link ResponseHeader#asMatcher(String) asMatcher(String)} <jk>returns</jk> {@link Matcher}</c> 600 * <li class='jm'><c>{@link ResponseHeader#asHeader(Class) asHeader(Class<T <jk>extends</jk> BasicHeader> c)} <jk>returns</jk> {@link BasicHeader}</c> 601 * <li class='jm'><c>{@link ResponseHeader#asStringHeader() asStringHeader()} <jk>returns</jk> {@link BasicStringHeader}</c> 602 * <li class='jm'><c>{@link ResponseHeader#asIntegerHeader() asIntegerHeader()} <jk>returns</jk> {@link BasicIntegerHeader}</c> 603 * <li class='jm'><c>{@link ResponseHeader#asLongHeader() asLongHeader()} <jk>returns</jk> {@link BasicLongHeader}</c> 604 * <li class='jm'><c>{@link ResponseHeader#asDateHeader() asDateHeader()} <jk>returns</jk> {@link BasicDateHeader}</c> 605 * <li class='jm'><c>{@link ResponseHeader#asCsvHeader() asCsvHeader()} <jk>returns</jk> {@link BasicCsvHeader}</c> 606 * <li class='jm'><c>{@link ResponseHeader#asEntityTagsHeader() asEntityTagsHeader()} <jk>returns</jk> {@link BasicEntityTagsHeader}</c> 607 * <li class='jm'><c>{@link ResponseHeader#asStringRangesHeader() asStringRangesHeader()} <jk>returns</jk> {@link BasicStringRangesHeader}</c> 608 * <li class='jm'><c>{@link ResponseHeader#asUriHeader() asUriHeader()} <jk>returns</jk> {@link BasicUriHeader}</c> 609 * </ul> 610 * </ul> 611 * 612 * <p> 613 * The {@link ResponseHeader#schema(HttpPartSchema)} method allows you to perform parsing of OpenAPI formats for 614 * header parts. 615 * 616 * <h5 class='figure'>Example:</h5> 617 * <p class='bjava'> 618 * <jc>// Parse the header "Foo: bar|baz".</jc> 619 * List<String> <jv>fooHeader</jv> = <jv>client</jv> 620 * .get(<jsf>URI</jsf>) 621 * .complete() 622 * .getHeader(<js>"Foo"</js>).schema(<jsf>T_ARRAY_PIPES</jsf>).as(List.<jk>class</jk>, String.<jk>class</jk>); 623 * </p> 624 * 625 * <p> 626 * Assertion methods are also provided for fluent-style calls: 627 * 628 * <ul class='javatree'> 629 * <li class='jc'>{@link ResponseHeader} 630 * <ul> 631 * <li class='jm'><c>{@link ResponseHeader#assertValue() assertValue()} <jk>returns</jk> {@link FluentResponseHeaderAssertion}</c> 632 * </ul> 633 * </ul> 634 * 635 * <p> 636 * Note how in the following example, the fluent assertion returns control to the {@link RestResponse} object after 637 * the assertion has been completed: 638 * 639 * <h5 class='figure'>Example:</h5> 640 * <p class='bjava'> 641 * <jc>// Assert the response content type is any sort of JSON.</jc> 642 * String <jv>body</jv> = <jv>client</jv>.get(<jsf>URI</jsf>) 643 * .run() 644 * .getHeader(<js>"Content-Type"</js>).assertValue().matchesSimple(<js>"application/json*"</js>) 645 * .getContent().asString(); 646 * </p> 647 * 648 * 649 * <h4 class='topic'>Response Body</h4> 650 * 651 * <p> 652 * The response body is accessed through the following method: 653 * 654 * <ul class='javatree'> 655 * <li class='jc'>{@link RestResponse} 656 * <ul> 657 * <li class='jm'><c>{@link RestResponse#getContent() getContent()} <jk>returns</jk> {@link ResponseContent}</c> 658 * </ul> 659 * </ul> 660 * 661 * <p> 662 * The {@link ResponseContent} class extends from the HttpClient {@link HttpEntity} class and provides several convenience 663 * methods: 664 * 665 * <ul class='javatree'> 666 * <li class='jc'>{@link ResponseContent} 667 * <ul> 668 * <li class='jm'><c>{@link ResponseContent#asInputStream() asInputStream()} <jk>returns</jk> InputStream</c> 669 * <li class='jm'><c>{@link ResponseContent#asReader() asReader()} <jk>returns</jk> Reader</c> 670 * <li class='jm'><c>{@link ResponseContent#asReader(Charset) asReader(Charset)} <jk>returns</jk> Reader</c> 671 * <li class='jm'><c>{@link ResponseContent#pipeTo(OutputStream) pipeTo(OutputStream)} <jk>returns</jk> {@link RestResponse}</c> 672 * <li class='jm'><c>{@link ResponseContent#pipeTo(Writer) pipeTo(Writer)} <jk>returns</jk> {@link RestResponse}</c> 673 * <li class='jm'><c>{@link ResponseContent#as(Type,Type...) as(Type,Type...)} <jk>returns</jk> T</c> 674 * <li class='jm'><c>{@link ResponseContent#as(Class) as(Class<T>)} <jk>returns</jk> T</c> 675 * <li class='jm'><c>{@link ResponseContent#asFuture(Class) asFuture(Class<T>)} <jk>returns</jk> Future<T></c> 676 * <li class='jm'><c>{@link ResponseContent#asFuture(Type,Type...) asFuture(Type,Type...)} <jk>returns</jk> Future<T></c> 677 * <li class='jm'><c>{@link ResponseContent#asString() asString()} <jk>returns</jk> String</c> 678 * <li class='jm'><c>{@link ResponseContent#asStringFuture() asStringFuture()} <jk>returns</jk> Future<String></c> 679 * <li class='jm'><c>{@link ResponseContent#asAbbreviatedString(int) asAbbreviatedString(int)} <jk>returns</jk> String</c> 680 * <li class='jm'><c>{@link ResponseContent#asObjectRest(Class) asObjectRest(Class<?>)} <jk>returns</jk> {@link ObjectRest}</c> 681 * <li class='jm'><c>{@link ResponseContent#asObjectRest() asObjectRest()} <jk>returns</jk> {@link ObjectRest}</c> 682 * <li class='jm'><c>{@link ResponseContent#asMatcher(Pattern) asMatcher(Pattern)} <jk>returns</jk> {@link Matcher}</c> 683 * <li class='jm'><c>{@link ResponseContent#asMatcher(String) asMatcher(String)} <jk>returns</jk> {@link Matcher}</c> 684 * </ul> 685 * </ul> 686 * 687 * <br> 688 * 689 * <h5 class='figure'>Examples:</h5> 690 * <p class='bjava'> 691 * <jc>// Parse into a linked-list of strings.</jc> 692 * List<String> <jv>list1</jv> = <jv>client</jv> 693 * .get(<jsf>URI</jsf>) 694 * .run() 695 * .getContent().as(LinkedList.<jk>class</jk>, String.<jk>class</jk>); 696 * 697 * <jc>// Parse into a linked-list of beans.</jc> 698 * List<MyBean> <jv>list2</jv> = <jv>client</jv> 699 * .get(<jsf>URI</jsf>) 700 * .run() 701 * .getContent().as(LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>); 702 * 703 * <jc>// Parse into a linked-list of linked-lists of strings.</jc> 704 * List<List<String>> <jv>list3</jv> = <jv>client</jv> 705 * .get(<jsf>URI</jsf>) 706 * .run() 707 * .getContent().as(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>); 708 * 709 * <jc>// Parse into a map of string keys/values.</jc> 710 * Map<String,String> <jv>map1</jv> = <jv>client</jv> 711 * .get(<jsf>URI</jsf>) 712 * .run() 713 * .getContent().as(TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>); 714 * 715 * <jc>// Parse into a map containing string keys and values of lists containing beans.</jc> 716 * Map<String,List<MyBean>> <jv>map2</jv> = <jv>client</jv> 717 * .get(<jsf>URI</jsf>) 718 * .run() 719 * .getContent().as(TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>); 720 * </p> 721 * 722 * <p> 723 * The response body can only be consumed once unless it has been cached into memory. In many cases, the body is 724 * automatically cached when using the assertions methods or methods such as {@link ResponseContent#asString()}. 725 * However, methods that involve reading directly from the input stream cannot be called twice. 726 * In these cases, the {@link RestResponse#cacheContent()} and {@link ResponseContent#cache()} methods are provided 727 * to cache the response body in memory so that you can perform several operations against it. 728 * 729 * <p class='bjava'> 730 * <jc>// Cache the response body so we can access it twice.</jc> 731 * InputStream <jv>inputStream</jv> = <jv>client</jv> 732 * .get(<jsf>URI</jsf>) 733 * .run() 734 * .cacheBody() 735 * .getContent().pipeTo(<jv>someOtherStream</jv>) 736 * .getContent().asInputStream(); 737 * </p> 738 * 739 * <p> 740 * Assertion methods are also provided for fluent-style calls: 741 * 742 * <ul class='javatree'> 743 * <li class='jc'>{@link ResponseContent} 744 * <ul> 745 * <li class='jm'><c>{@link ResponseContent#assertValue() assertValue()} <jk>returns</jk> {@link FluentResponseBodyAssertion}</c> 746 * </ul> 747 * </ul> 748 * 749 * <br> 750 * 751 * <h5 class='figure'>Example:</h5> 752 * <p class='bjava'> 753 * <jc>// Assert that the body contains the string "Success".</jc> 754 * String <jv>body</jv> = <jv>client</jv> 755 * .get(<jsf>URI</jsf>) 756 * .run() 757 * .getContent().assertString().contains(<js>"Success"</js>) 758 * .getContent().asString(); 759 * </p> 760 * 761 * <p> 762 * Object assertions allow you to parse the response body into a POJO and then perform various tests on that resulting 763 * POJO. 764 * 765 * <h5 class='figure'>Example:</h5> 766 * <p class='bjava'> 767 * <jc>// Parse bean into POJO and then validate that it was parsed correctly.</jc> 768 * MyBean <jv>bean</jv> = <jv>client</jv>.get(<jsf>URI</jsf>) 769 * .run() 770 * .getContent().assertObject(MyBean.<jk>class</jk>).asJson().is(<js>"{foo:'bar'}"</js>) 771 * .getContent().as(MyBean.<jk>class</jk>); 772 * </p> 773 * 774 * 775 * <h4 class='topic'>Custom Call Handlers</h4> 776 * 777 * <p> 778 * The {@link RestCallHandler} interface provides the ability to provide custom handling of requests. 779 * 780 * <ul class='javatree'> 781 * <li class='jc'>{@link Builder} 782 * <ul> 783 * <li class='jm'>{@link Builder#callHandler() callHandler()} 784 * </ul> 785 * <li class='jic'>{@link RestCallHandler} 786 * <ul> 787 * <li class='jm'><c>{@link RestCallHandler#run(HttpHost,HttpRequest,HttpContext) run(HttpHost,HttpRequest,HttpContext)} <jk>returns</jk> HttpResponse</c> 788 * </ul> 789 * </ul> 790 * 791 * <p> 792 * Note that there are other ways of accomplishing this such as extending the {@link RestClient} class and overriding 793 * the {@link #run(HttpHost,HttpRequest,HttpContext)} method 794 * or by defining your own {@link HttpRequestExecutor}. Using this interface is often simpler though. 795 * 796 * 797 * <h4 class='topic'>Interceptors</h4> 798 * 799 * <p> 800 * The {@link RestCallInterceptor} API provides a quick way of intercepting and manipulating requests and responses beyond 801 * the existing {@link HttpRequestInterceptor} and {@link HttpResponseInterceptor} APIs. 802 * 803 * <ul class='javatree'> 804 * <li class='jc'>{@link Builder} 805 * <ul> 806 * <li class='jm'>{@link Builder#interceptors(Object...) interceptors(Object...)} 807 * </ul> 808 * <li class='jc'>{@link RestRequest} 809 * <ul> 810 * <li class='jm'>{@link RestRequest#interceptors(RestCallInterceptor...) interceptors(RestCallInterceptor...)} 811 * </ul> 812 * <li class='jic'>{@link RestCallInterceptor} 813 * <ul> 814 * <li class='jm'>{@link RestCallInterceptor#onInit(RestRequest) onInit(RestRequest)} 815 * <li class='jm'>{@link RestCallInterceptor#onConnect(RestRequest,RestResponse) onConnect(RestRequest,RestResponse)} 816 * <li class='jm'>{@link RestCallInterceptor#onClose(RestRequest,RestResponse) onClose(RestRequest,RestResponse)} 817 * </ul> 818 * </ul> 819 * 820 * 821 * <h4 class='topic'>Logging / Debugging</h4> 822 * 823 * <p> 824 * The following methods provide logging of requests and responses: 825 * 826 * <ul class='javatree'> 827 * <li class='jc'>{@link Builder} 828 * <ul> 829 * <li class='jm'>{@link Builder#logger(Logger) logger(Logger)} 830 * <li class='jm'>{@link Builder#logToConsole() logToConsole()} 831 * <li class='jm'>{@link Builder#logRequests(DetailLevel,Level,BiPredicate) logRequests(DetailLevel,Level,BiPredicate)} 832 * </ul> 833 * </ul> 834 * 835 * <p> 836 * The following example shows the results of logging all requests that end with <c>/bean</c>. 837 * 838 * <h5 class='figure'>Examples:</h5> 839 * <p class='bjava'> 840 * MyBean <jv>bean</jv> = RestClient 841 * .<jsm>create</jsm>() 842 * .json5() 843 * .logRequests(DetailLevel.<jsf>FULL</jsf>, Level.<jsf>SEVERE</jsf>, (<jv>req</jv>,<jv>res</jv>)-><jv>req</jv>.getUri().endsWith(<js>"/bean"</js>)) 844 * .logToConsole() 845 * .build() 846 * .post(<js>"http://localhost/bean"</js>, <jv>anotherBean</jv>) 847 * .run() 848 * .getContent().as(MyBean.<jk>class</jk>); 849 * </p> 850 * 851 * <p> 852 * This produces the following console output: 853 * 854 * <p class='bconsole'> 855 * === HTTP Call (outgoing) ====================================================== 856 * === REQUEST === 857 * POST http://localhost/bean 858 * ---request headers--- 859 * Accept: application/json5 860 * ---request entity--- 861 * Content-Type: application/json5 862 * ---request content--- 863 * {f:1} 864 * === RESPONSE === 865 * HTTP/1.1 200 866 * ---response headers--- 867 * Content-Type: application/json 868 * ---response content--- 869 * {f:1} 870 * === END =======================================================================", 871 * </p> 872 * 873 * 874 * <p class='notes'> 875 * It should be noted that if you enable request logging detail level {@link DetailLevel#FULL}, response bodies will be cached by default which may introduce 876 * a performance penalty. 877 * 878 * <p> 879 * Additionally, the following method is also provided for enabling debug mode: 880 * 881 * <ul class='javatree'> 882 * <li class='jc'>{@link Builder} 883 * <ul> 884 * <li class='jm'>{@link Builder#debug() debug()} 885 * </ul> 886 * </ul> 887 * 888 * <p> 889 * Enabling debug mode has the following effects: 890 * <ul> 891 * <li>{@link org.apache.juneau.Context.Builder#debug()} is enabled. 892 * <li>{@link Builder#detectLeaks()} is enabled. 893 * <li>{@link Builder#logToConsole()} is called. 894 * </ul> 895 * 896 * 897 * <h4 class='topic'>REST Proxies</h4> 898 * 899 * <p> 900 * One of the more powerful features of the REST client class is the ability to produce Java interface proxies against 901 * arbitrary remote REST resources. 902 * 903 * <h5 class='figure'>Example:</h5> 904 * <p class='bjava'> 905 * <jc>// Define a Remote proxy for interacting with a REST interface.</jc> 906 * <ja>@Remote</ja>(path=<js>"/petstore"</js>) 907 * <jk>public interface</jk> PetStore { 908 * 909 * <ja>@RemotePost</ja>(<js>"/pets"</js>) 910 * Pet addPet( 911 * <ja>@Content</ja> CreatePet <jv>pet</jv>, 912 * <ja>@Header</ja>(<js>"E-Tag"</js>) UUID <jv>etag</jv>, 913 * <ja>@Query</ja>(<js>"debug"</js>) <jk>boolean</jk> <jv>debug</jv> 914 * ); 915 * } 916 * 917 * <jc>// Use a RestClient with default JSON 5 support.</jc> 918 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().json5().build()) 919 * 920 * PetStore <jv>store</jv> = <jv>client</jv>.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>); 921 * CreatePet <jv>createPet</jv> = <jk>new</jk> CreatePet(<js>"Fluffy"</js>, 9.99); 922 * Pet <jv>pet</jv> = <jv>store</jv>.addPet(<jv>createPet</jv>, UUID.<jsm>randomUUID</jsm>(), <jk>true</jk>); 923 * </p> 924 * 925 * <p> 926 * The methods to retrieve remote interfaces are: 927 * 928 * <ul class='javatree'> 929 * <li class='jc'>{@link RestClient} 930 * <ul> 931 * <li class='jm'><c>{@link RestClient#getRemote(Class) getRemote(Class<T>)} <jk>returns</jk> T</c> 932 * <li class='jm'><c>{@link RestClient#getRemote(Class,Object) getRemote(Class<T>,Object)} <jk>returns</jk> T</c> 933 * <li class='jm'><c>{@link RestClient#getRemote(Class,Object,Serializer,Parser) getRemote(Class<T>,Object,Serializer,Parser)} <jk>returns</jk> T</c> 934 * <li class='jm'><c>{@link RestClient#getRrpcInterface(Class) getRrpcInterface(Class<T>)} <jk>returns</jk> T</c> 935 * <li class='jm'><c>{@link RestClient#getRrpcInterface(Class,Object) getRrpcInterface(Class<T>,Object)} <jk>returns</jk> T</c> 936 * <li class='jm'><c>{@link RestClient#getRrpcInterface(Class,Object,Serializer,Parser) getRrpcInterface(Class<T>,Object,Serializer,Parser)} <jk>returns</jk> T</c> 937 * </ul> 938 * </ul> 939 * 940 * <p> 941 * Two basic types of remote interfaces are provided: 942 * 943 * <ul class='spaced-list'> 944 * <li>{@link Remote @Remote}-annotated interfaces. These can be defined against arbitrary external REST resources. 945 * <li>RPC-over-REST interfaces. These are Java interfaces that allow you to make method calls on server-side POJOs. 946 * </ul> 947 * 948 * <p> 949 * Refer to the following documentation on both flavors: 950 * 951 * <ul class='doctree'> 952 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestProxyBasics">REST Proxy Basics</a> 953 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestRpc">REST/RPC</a> 954 * </ul> 955 * 956 * <br> 957 * <hr> 958 * <h4 class='topic'>Customizing Apache HttpClient</h4> 959 * 960 * <p> 961 * Several methods are provided for customizing the underlying HTTP client and client builder classes: 962 * <ul class='javatree'> 963 * <li class='jc'>{@link Builder} 964 * <ul> 965 * <li class='jm'>{@link Builder#httpClientBuilder(HttpClientBuilder) httpClientBuilder(HttpClientBuilder)} - Set the client builder yourself. 966 * <li class='jm'>{@link Builder#createHttpClientBuilder() createHttpClientBuilder()} - Override to create the client builder. 967 * <li class='jm'>{@link Builder#createHttpClient() createHttpClient()} - Override to create the client. 968 * <li class='jm'>{@link Builder#createConnectionManager() createConnectionManager()} - Override to create the connection management. 969 * </ul> 970 * </ul> 971 * 972 * <p> 973 * Additionally, all methods on the <c>HttpClientBuilder</c> class have been extended with fluent setters. 974 * 975 * <h5 class='figure'>Example:</h5> 976 * <p class='bjava'> 977 * <jc>// Create a client with customized HttpClient settings.</jc> 978 * MyBean <jv>bean</jv> = RestClient 979 * .<jsm>create</jsm>() 980 * .disableRedirectHandling() 981 * .connectionManager(<jv>myConnectionManager</jv>) 982 * .addInterceptorFirst(<jv>myHttpRequestInterceptor</jv>) 983 * .build(); 984 * </p> 985 * 986 * <p> 987 * Refer to the {@link HttpClientBuilder HTTP Client Builder API} for more information. 988 * 989 * 990 * <h4 class='topic'>Extending RestClient</h4> 991 * 992 * <p> 993 * The <c>RestClient</c> API has been designed to allow for the ability to be easily extended. 994 * The following example that overrides the primary run method shows how this can be done. 995 * 996 * <h5 class='figure'>Example:</h5> 997 * <p class='bjava'> 998 * <jk>public class</jk> MyRestClient <jk>extends</jk> RestClient { 999 * 1000 * <jc>// Must provide this constructor!</jc> 1001 * <jk>public</jk> MyRestClient(RestClient.Builder <jv>builder</jv>) { 1002 * <jk>super</jk>(<jv>builder</jv>); 1003 * } 1004 * 1005 * <jd>/** Optionally override to customize builder settings before initialization. </jd> 1006 * <ja>@Override</ja> 1007 * <jk>protected void</jk> init(RestClient.Builder) {...} 1008 * 1009 * <jd>/** Optionally override to provide post-initialization (e.g. setting up SAML handshakes, etc...). </jd> 1010 * <ja>@Override</ja> 1011 * <jk>protected void</jk> init() {...} 1012 * 1013 * <jd>/** Optionally override to customize requests when they're created (e.g. add headers to each request). </jd> 1014 * <ja>@Override</ja> 1015 * <jk>protected</jk> RestRequest request(RestOperation) {...} 1016 * 1017 * <jd>/** Optionally override to implement your own call handling. </jd> 1018 * <ja>@Override</ja> 1019 * <jk>protected</jk> HttpResponse run(HttpHost, HttpRequest, HttpContext) {...} 1020 * 1021 * <jd>/** Optionally override to customize requests before they're executed. </jd> 1022 * <ja>@Override</ja> 1023 * <jk>protected void</jk> onCallInit(RestRequest) {...} 1024 * 1025 * <jd>/** Optionally override to customize responses as soon as a connection is made. </jd> 1026 * <ja>@Override</ja> 1027 * <jk>protected void</jk> onCallConnect(RestRequest, RestResponse) {...} 1028 * 1029 * <jd>/** Optionally override to perform any call cleanup. </jd> 1030 * <ja>@Override</ja> 1031 * <jk>protected void</jk> onCallClose(RestRequest, RestResponse) {...} 1032 * } 1033 * 1034 * <jc>// Instantiate your client.</jc> 1035 * MyRestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().json().build(MyRestClient.<jk>class</jk>); 1036 * </p> 1037 * 1038 * <p> 1039 * The {@link RestRequest} and {@link RestResponse} objects can also be extended and integrated by overriding the 1040 * {@link RestClient#createRequest(URI,String,boolean)} and {@link RestClient#createResponse(RestRequest,HttpResponse,Parser)} methods. 1041 * 1042 * <h5 class='section'>Notes:</h5><ul> 1043 * <li class='note'>This class is thread safe and reusable. 1044 * </ul> 1045 * 1046 * <h5 class='section'>See Also:</h5><ul> 1047 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestClientBasics">juneau-rest-client Basics</a> 1048 * </ul> 1049 */ 1050public class RestClient extends BeanContextable implements HttpClient, Closeable { 1051 1052 //------------------------------------------------------------------------------------------------------------------- 1053 // Static 1054 //------------------------------------------------------------------------------------------------------------------- 1055 1056 private static final RestCallInterceptor[] EMPTY_REST_CALL_INTERCEPTORS = {}; 1057 1058 /** 1059 * Instantiates a new clean-slate {@link Builder} object. 1060 * 1061 * @return A new {@link Builder} object. 1062 */ 1063 public static Builder create() { 1064 return new Builder(); 1065 } 1066 1067 //------------------------------------------------------------------------------------------------------------------- 1068 // Builder 1069 //------------------------------------------------------------------------------------------------------------------- 1070 1071 /** 1072 * Builder class. 1073 */ 1074 public static class Builder extends BeanContextable.Builder { 1075 1076 BeanStore beanStore = BeanStore.create().build(); 1077 1078 private HttpClientBuilder httpClientBuilder; 1079 private CloseableHttpClient httpClient; 1080 1081 private HeaderList headerData; 1082 private PartList queryData, formData, pathData; 1083 private BeanCreator<RestCallHandler> callHandler; 1084 private SerializerSet.Builder serializers; 1085 private ParserSet.Builder parsers; 1086 private HttpPartSerializer.Creator partSerializer; 1087 private HttpPartParser.Creator partParser; 1088 private UrlEncodingSerializer.Builder urlEncodingSerializer; 1089 1090 private boolean pooled; 1091 1092 String rootUrl; 1093 boolean skipEmptyHeaderData, skipEmptyFormData, skipEmptyQueryData, executorServiceShutdownOnClose, ignoreErrors, keepHttpClientOpen, detectLeaks, 1094 logToConsole; 1095 Logger logger; 1096 DetailLevel logRequests; 1097 Level logRequestsLevel; 1098 BiPredicate<RestRequest,RestResponse> logRequestsPredicate; 1099 Predicate<Integer> errorCodes = x -> x<=0 || x>=400; 1100 HttpClientConnectionManager connectionManager; 1101 PrintStream console; 1102 ExecutorService executorService; 1103 List<RestCallInterceptor> interceptors; 1104 1105 /** 1106 * Constructor. 1107 */ 1108 protected Builder() { 1109 } 1110 1111 @Override /* Context.Builder */ 1112 public Builder copy() { 1113 throw new NoSuchMethodError("Not implemented."); 1114 } 1115 1116 @Override /* Context.Builder */ 1117 public RestClient build() { 1118 return build(RestClient.class); 1119 } 1120 1121 //------------------------------------------------------------------------------------------------------------------ 1122 // Convenience marshalling support methods. 1123 //------------------------------------------------------------------------------------------------------------------ 1124 1125 /** 1126 * Convenience method for specifying JSON as the marshalling transmission media type. 1127 * 1128 * <p> 1129 * {@link JsonSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 1130 * <ul> 1131 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or 1132 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1133 * </ul> 1134 * <p> 1135 * {@link JsonParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 1136 * <ul> 1137 * <li>The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or 1138 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1139 * </ul> 1140 * <p> 1141 * <c>Accept</c> request header will be set to <js>"application/json"</js> unless overridden 1142 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}}. 1143 * <p> 1144 * <c>Content-Type</c> request header will be set to <js>"application/json"</js> unless overridden 1145 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1146 * <p> 1147 * Can be combined with other marshaller setters such as {@link #xml()} to provide support for multiple languages. 1148 * <ul> 1149 * <li>When multiple languages are supported, the <c>Accept</c> and <c>Content-Type</c> headers control which marshallers are used, or uses the 1150 * last-enabled language if the headers are not set. 1151 * </ul> 1152 * <p> 1153 * Identical to calling <c>serializer(JsonSerializer.<jk>class</jk>).parser(JsonParser.<jk>class</jk>)</c>. 1154 * 1155 * <h5 class='section'>Example:</h5> 1156 * <p class='bjava'> 1157 * <jc>// Construct a client that uses JSON marshalling.</jc> 1158 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().json().build(); 1159 * </p> 1160 * 1161 * @return This object. 1162 */ 1163 public Builder json() { 1164 return serializer(JsonSerializer.class).parser(JsonParser.class); 1165 } 1166 1167 /** 1168 * Convenience method for specifying Simplified JSON as the marshalling transmission media type. 1169 * 1170 * <p> 1171 * Simplified JSON is typically useful for automated tests because you can do simple string comparison of results 1172 * without having to escape lots of quotes. 1173 * 1174 * <p> 1175 * {@link Json5Serializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 1176 * <ul> 1177 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or 1178 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1179 * </ul> 1180 * <p> 1181 * {@link Json5Parser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 1182 * <ul> 1183 * <li>The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or 1184 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1185 * </ul> 1186 * <p> 1187 * <c>Accept</c> request header will be set to <js>"application/json"</js> unless overridden 1188 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1189 * <p> 1190 * <c>Content-Type</c> request header will be set to <js>"application/json5"</js> unless overridden 1191 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1192 * <p> 1193 * Can be combined with other marshaller setters such as {@link #xml()} to provide support for multiple languages. 1194 * <ul> 1195 * <li>When multiple languages are supported, the <c>Accept</c> and <c>Content-Type</c> headers control which marshallers are used, or uses the 1196 * last-enabled language if the headers are not set. 1197 * </ul> 1198 * <p> 1199 * Identical to calling <c>serializer(Json5Serializer.<jk>class</jk>).parser(Json5Parser.<jk>class</jk>)</c>. 1200 * 1201 * <h5 class='section'>Example:</h5> 1202 * <p class='bjava'> 1203 * <jc>// Construct a client that uses Simplified JSON marshalling.</jc> 1204 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().json5().build(); 1205 * </p> 1206 * 1207 * @return This object. 1208 */ 1209 public Builder json5() { 1210 return serializer(Json5Serializer.class).parser(Json5Parser.class); 1211 } 1212 1213 /** 1214 * Convenience method for specifying XML as the marshalling transmission media type. 1215 * 1216 * <p> 1217 * {@link XmlSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 1218 * <ul> 1219 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or 1220 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1221 * </ul> 1222 * <p> 1223 * {@link XmlParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 1224 * <ul> 1225 * <li>The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or 1226 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1227 * </ul> 1228 * <p> 1229 * <c>Accept</c> request header will be set to <js>"text/xml"</js> unless overridden 1230 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1231 * <p> 1232 * <c>Content-Type</c> request header will be set to <js>"text/xml"</js> unless overridden 1233 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1234 * <p> 1235 * Can be combined with other marshaller setters such as {@link #json()} to provide support for multiple languages. 1236 * <ul> 1237 * <li>When multiple languages are supported, the <c>Accept</c> and <c>Content-Type</c> headers control which marshallers are used, or uses the 1238 * last-enabled language if the headers are not set. 1239 * </ul> 1240 * <p> 1241 * Identical to calling <c>serializer(XmlSerializer.<jk>class</jk>).parser(XmlParser.<jk>class</jk>)</c>. 1242 * 1243 * <h5 class='section'>Example:</h5> 1244 * <p class='bjava'> 1245 * <jc>// Construct a client that uses XML marshalling.</jc> 1246 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().xml().build(); 1247 * </p> 1248 * 1249 * @return This object. 1250 */ 1251 public Builder xml() { 1252 return serializer(XmlSerializer.class).parser(XmlParser.class); 1253 } 1254 1255 /** 1256 * Convenience method for specifying HTML as the marshalling transmission media type. 1257 * 1258 * <p> 1259 * POJOs are converted to HTML without any sort of doc wrappers. 1260 * 1261 * <p> 1262 * {@link HtmlSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 1263 * <ul> 1264 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or 1265 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1266 * </ul> 1267 * <p> 1268 * {@link HtmlParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 1269 * <ul> 1270 * <li>The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or 1271 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1272 * </ul> 1273 * <p> 1274 * <c>Accept</c> request header will be set to <js>"text/html"</js> unless overridden 1275 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1276 * <p> 1277 * <c>Content-Type</c> request header will be set to <js>"text/html"</js> unless overridden 1278 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1279 * <p> 1280 * Can be combined with other marshaller setters such as {@link #json()} to provide support for multiple languages. 1281 * <ul> 1282 * <li>When multiple languages are supported, the <c>Accept</c> and <c>Content-Type</c> headers control which marshallers are used, or uses the 1283 * last-enabled language if the headers are not set. 1284 * </ul> 1285 * <p> 1286 * Identical to calling <c>serializer(HtmlSerializer.<jk>class</jk>).parser(HtmlParser.<jk>class</jk>)</c>. 1287 * 1288 * <h5 class='section'>Example:</h5> 1289 * <p class='bjava'> 1290 * <jc>// Construct a client that uses HTML marshalling.</jc> 1291 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().html().build(); 1292 * </p> 1293 * 1294 * @return This object. 1295 */ 1296 public Builder html() { 1297 return serializer(HtmlSerializer.class).parser(HtmlParser.class); 1298 } 1299 1300 /** 1301 * Convenience method for specifying HTML DOC as the marshalling transmission media type. 1302 * 1303 * <p> 1304 * POJOs are converted to fully renderable HTML pages. 1305 * 1306 * <p> 1307 * {@link HtmlDocSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 1308 * <ul> 1309 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()} or 1310 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1311 * </ul> 1312 * <p> 1313 * {@link HtmlParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 1314 * <ul> 1315 * <li>The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or 1316 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1317 * </ul> 1318 * <p> 1319 * <c>Accept</c> request header will be set to <js>"text/html"</js> unless overridden 1320 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1321 * <p> 1322 * <c>Content-Type</c> request header will be set to <js>"text/html"</js> unless overridden 1323 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1324 * <p> 1325 * Can be combined with other marshaller setters such as {@link #json()} to provide support for multiple languages. 1326 * <ul> 1327 * <li>When multiple languages are supported, the <c>Accept</c> and <c>Content-Type</c> headers control which marshallers are used, or uses the 1328 * last-enabled language if the headers are not set. 1329 * </ul> 1330 * <p> 1331 * Identical to calling <c>serializer(HtmlDocSerializer.<jk>class</jk>).parser(HtmlParser.<jk>class</jk>)</c>. 1332 * 1333 * <h5 class='section'>Example:</h5> 1334 * <p class='bjava'> 1335 * <jc>// Construct a client that uses HTML Doc marshalling.</jc> 1336 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().htmlDoc().build(); 1337 * </p> 1338 * 1339 * @return This object. 1340 */ 1341 public Builder htmlDoc() { 1342 return serializer(HtmlDocSerializer.class).parser(HtmlParser.class); 1343 } 1344 1345 /** 1346 * Convenience method for specifying Stripped HTML DOC as the marshalling transmission media type. 1347 * 1348 * <p> 1349 * Same as {@link #htmlDoc()} but without the header and body tags and page title and description. 1350 * 1351 * <p> 1352 * {@link HtmlStrippedDocSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 1353 * <ul> 1354 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or 1355 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1356 * </ul> 1357 * <p> 1358 * {@link HtmlParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 1359 * <ul> 1360 * <li>The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or 1361 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1362 * </ul> 1363 * <p> 1364 * <c>Accept</c> request header will be set to <js>"text/html+stripped"</js> unless overridden 1365 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1366 * <p> 1367 * <c>Content-Type</c> request header will be set to <js>"text/html+stripped"</js> unless overridden 1368 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1369 * <p> 1370 * Can be combined with other marshaller setters such as {@link #json()} to provide support for multiple languages. 1371 * <ul> 1372 * <li>When multiple languages are supported, the <c>Accept</c> and <c>Content-Type</c> headers control which marshallers are used, or uses the 1373 * last-enabled language if the headers are not set. 1374 * </ul> 1375 * <p> 1376 * Identical to calling <c>serializer(HtmlStrippedDocSerializer.<jk>class</jk>).parser(HtmlParser.<jk>class</jk>)</c>. 1377 * 1378 * <h5 class='section'>Example:</h5> 1379 * <p class='bjava'> 1380 * <jc>// Construct a client that uses HTML Stripped Doc marshalling.</jc> 1381 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().htmlStrippedDoc().build(); 1382 * </p> 1383 * 1384 * @return This object. 1385 */ 1386 public Builder htmlStrippedDoc() { 1387 return serializer(HtmlStrippedDocSerializer.class).parser(HtmlParser.class); 1388 } 1389 1390 /** 1391 * Convenience method for specifying Plain Text as the marshalling transmission media type. 1392 * 1393 * <p> 1394 * Plain text marshalling typically only works on simple POJOs that can be converted to and from strings using 1395 * swaps, swap methods, etc... 1396 * 1397 * <p> 1398 * {@link PlainTextSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 1399 * <ul> 1400 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or 1401 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1402 * </ul> 1403 * <p> 1404 * {@link PlainTextParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 1405 * <ul> 1406 * <li>The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or 1407 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1408 * </ul> 1409 * <p> 1410 * <c>Accept</c> request header will be set to <js>"text/plain"</js> unless overridden 1411 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1412 * <p> 1413 * <c>Content-Type</c> request header will be set to <js>"text/plain"</js> unless overridden 1414 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1415 * <p> 1416 * Can be combined with other marshaller setters such as {@link #json()} to provide support for multiple languages. 1417 * <ul> 1418 * <li>When multiple languages are supported, the <c>Accept</c> and <c>Content-Type</c> headers control which marshallers are used, or uses the 1419 * last-enabled language if the headers are not set. 1420 * </ul> 1421 * <p> 1422 * Identical to calling <c>serializer(PlainTextSerializer.<jk>class</jk>).parser(PlainTextParser.<jk>class</jk>)</c>. 1423 * 1424 * <h5 class='section'>Example:</h5> 1425 * <p class='bjava'> 1426 * <jc>// Construct a client that uses Plain Text marshalling.</jc> 1427 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().plainText().build(); 1428 * </p> 1429 * 1430 * @return This object. 1431 */ 1432 public Builder plainText() { 1433 return serializer(PlainTextSerializer.class).parser(PlainTextParser.class); 1434 } 1435 1436 /** 1437 * Convenience method for specifying MessagePack as the marshalling transmission media type. 1438 * 1439 * <p> 1440 * MessagePack is a binary equivalent to JSON that takes up considerably less space than JSON. 1441 * 1442 * <p> 1443 * {@link MsgPackSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 1444 * <ul> 1445 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or 1446 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1447 * </ul> 1448 * <p> 1449 * {@link MsgPackParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 1450 * <ul> 1451 * <li>The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or 1452 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1453 * </ul> 1454 * <p> 1455 * <c>Accept</c> request header will be set to <js>"octal/msgpack"</js> unless overridden 1456 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1457 * <p> 1458 * <c>Content-Type</c> request header will be set to <js>"octal/msgpack"</js> unless overridden 1459 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1460 * <p> 1461 * Can be combined with other marshaller setters such as {@link #json()} to provide support for multiple languages. 1462 * <ul> 1463 * <li>When multiple languages are supported, the <c>Accept</c> and <c>Content-Type</c> headers control which marshallers are used, or uses the 1464 * last-enabled language if the headers are not set. 1465 * </ul> 1466 * <p> 1467 * Identical to calling <c>serializer(MsgPackSerializer.<jk>class</jk>).parser(MsgPackParser.<jk>class</jk>)</c>. 1468 * 1469 * <h5 class='section'>Example:</h5> 1470 * <p class='bjava'> 1471 * <jc>// Construct a client that uses MessagePack marshalling.</jc> 1472 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().msgPack().build(); 1473 * </p> 1474 * 1475 * @return This object. 1476 */ 1477 public Builder msgPack() { 1478 return serializer(MsgPackSerializer.class).parser(MsgPackParser.class); 1479 } 1480 1481 /** 1482 * Convenience method for specifying UON as the marshalling transmission media type. 1483 * 1484 * <p> 1485 * UON is Url-Encoding Object notation that is equivalent to JSON but suitable for transmission as URL-encoded 1486 * query and form post values. 1487 * 1488 * <p> 1489 * {@link UonSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 1490 * <ul> 1491 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or 1492 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1493 * </ul> 1494 * <p> 1495 * {@link UonParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 1496 * <ul> 1497 * <li>The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or 1498 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1499 * </ul> 1500 * <p> 1501 * <c>Accept</c> request header will be set to <js>"text/uon"</js> unless overridden 1502 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1503 * <p> 1504 * <c>Content-Type</c> request header will be set to <js>"text/uon"</js> unless overridden 1505 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1506 * <p> 1507 * Can be combined with other marshaller setters such as {@link #json()} to provide support for multiple languages. 1508 * <ul> 1509 * <li>When multiple languages are supported, the <c>Accept</c> and <c>Content-Type</c> headers control which marshallers are used, or uses the 1510 * last-enabled language if the headers are not set. 1511 * </ul> 1512 * <p> 1513 * Identical to calling <c>serializer(UonSerializer.<jk>class</jk>).parser(UonParser.<jk>class</jk>)</c>. 1514 * 1515 * <h5 class='section'>Example:</h5> 1516 * <p class='bjava'> 1517 * <jc>// Construct a client that uses UON marshalling.</jc> 1518 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().uon().build(); 1519 * </p> 1520 * 1521 * @return This object. 1522 */ 1523 public Builder uon() { 1524 return serializer(UonSerializer.class).parser(UonParser.class); 1525 } 1526 1527 /** 1528 * Convenience method for specifying URL-Encoding as the marshalling transmission media type. 1529 * 1530 * <p> 1531 * {@link UrlEncodingSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 1532 * <ul> 1533 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or 1534 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1535 * <li>This serializer is NOT used when using the {@link RestRequest#formData(String, Object)} (and related) methods for constructing 1536 * the request body. Instead, the part serializer specified via {@link #partSerializer(Class)} is used. 1537 * </ul> 1538 * <p> 1539 * {@link UrlEncodingParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 1540 * <ul> 1541 * <li>The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or 1542 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1543 * </ul> 1544 * <p> 1545 * <c>Accept</c> request header will be set to <js>"application/x-www-form-urlencoded"</js> unless overridden 1546 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1547 * <p> 1548 * <c>Content-Type</c> request header will be set to <js>"application/x-www-form-urlencoded"</js> unless overridden 1549 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1550 * <p> 1551 * Can be combined with other marshaller setters such as {@link #json()} to provide support for multiple languages. 1552 * <ul> 1553 * <li>When multiple languages are supported, the <c>Accept</c> and <c>Content-Type</c> headers control which marshallers are used, or uses the 1554 * last-enabled language if the headers are not set. 1555 * </ul> 1556 * <p> 1557 * Identical to calling <c>serializer(UrlEncodingSerializer.<jk>class</jk>).parser(UrlEncodingParser.<jk>class</jk>)</c>. 1558 * 1559 * <h5 class='section'>Example:</h5> 1560 * <p class='bjava'> 1561 * <jc>// Construct a client that uses URL-Encoded marshalling.</jc> 1562 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().urlEnc().build(); 1563 * </p> 1564 * 1565 * @return This object. 1566 */ 1567 public Builder urlEnc() { 1568 return serializer(UrlEncodingSerializer.class).parser(UrlEncodingParser.class); 1569 } 1570 1571 /** 1572 * Convenience method for specifying OpenAPI as the marshalling transmission media type. 1573 * 1574 * <p> 1575 * OpenAPI is a language that allows serialization to formats that use {@link HttpPartSchema} objects to describe their structure. 1576 * 1577 * <p> 1578 * {@link OpenApiSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 1579 * <ul> 1580 * <li>The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or 1581 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1582 * <li>Typically the {@link RestRequest#content(Object, HttpPartSchema)} method will be used to specify the body of the request with the 1583 * schema describing it's structure. 1584 * </ul> 1585 * <p> 1586 * {@link OpenApiParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 1587 * <ul> 1588 * <li>The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or 1589 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1590 * <li>Typically the {@link ResponseContent#schema(HttpPartSchema)} method will be used to specify the structure of the response body. 1591 * </ul> 1592 * <p> 1593 * <c>Accept</c> request header will be set to <js>"text/openapi"</js> unless overridden 1594 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1595 * <p> 1596 * <c>Content-Type</c> request header will be set to <js>"text/openapi"</js> unless overridden 1597 * via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}. 1598 * <p> 1599 * Can be combined with other marshaller setters such as {@link #json()} to provide support for multiple languages. 1600 * <ul> 1601 * <li>When multiple languages are supported, the <c>Accept</c> and <c>Content-Type</c> headers control which marshallers are used, or uses the 1602 * last-enabled language if the headers are not set. 1603 * </ul> 1604 * <p> 1605 * Identical to calling <c>serializer(OpenApiSerializer.<jk>class</jk>).parser(OpenApiParser.<jk>class</jk>)</c>. 1606 * 1607 * <h5 class='section'>Example:</h5> 1608 * <p class='bjava'> 1609 * <jc>// Construct a client that uses OpenAPI marshalling.</jc> 1610 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().openApi().build(); 1611 * </p> 1612 * 1613 * @return This object. 1614 */ 1615 public Builder openApi() { 1616 return serializer(OpenApiSerializer.class).parser(OpenApiParser.class); 1617 } 1618 1619 /** 1620 * Convenience method for specifying all available transmission types. 1621 * 1622 * <p> 1623 * All basic Juneau serializers will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}. 1624 * <ul> 1625 * <li>The serializers can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or 1626 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1627 * </ul> 1628 * <p> 1629 * All basic Juneau parsers will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}. 1630 * <ul> 1631 * <li>The parsers can be configured using any of the parser property setters (e.g. {@link #strict()}) or 1632 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1633 * </ul> 1634 * <p> 1635 * <c>Accept</c> request header must be set via {@link #headers()}, or per-request 1636 * via {@link RestRequest#header(Header)} in order for the correct parser to be selected. 1637 * <p> 1638 * <c>Content-Type</c> request header must be set via {@link #headers()}, 1639 * or per-request via {@link RestRequest#header(Header)} in order for the correct serializer to be selected. 1640 * <p> 1641 * Similar to calling <c>json().json5().html().xml().uon().urlEnc().openApi().msgPack().plainText()</c>. 1642 * 1643 * <h5 class='section'>Example:</h5> 1644 * <p class='bjava'> 1645 * <jc>// Construct a client that uses universal marshalling.</jc> 1646 * RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().universal().build(); 1647 * </p> 1648 * 1649 * @return This object. 1650 */ 1651 @SuppressWarnings("unchecked") 1652 public Builder universal() { 1653 return 1654 serializers( 1655 JsonSerializer.class, 1656 Json5Serializer.class, 1657 HtmlSerializer.class, 1658 XmlSerializer.class, 1659 UonSerializer.class, 1660 UrlEncodingSerializer.class, 1661 OpenApiSerializer.class, 1662 MsgPackSerializer.class, 1663 PlainTextSerializer.class 1664 ) 1665 .parsers( 1666 JsonParser.class, 1667 Json5Parser.class, 1668 XmlParser.class, 1669 HtmlParser.class, 1670 UonParser.class, 1671 UrlEncodingParser.class, 1672 OpenApiParser.class, 1673 MsgPackParser.class, 1674 PlainTextParser.class 1675 ); 1676 } 1677 1678 //------------------------------------------------------------------------------------------------------------------ 1679 // httpClientBuilder 1680 //------------------------------------------------------------------------------------------------------------------ 1681 1682 /** 1683 * Returns the HTTP client builder. 1684 * 1685 * @return The HTTP client builder. 1686 */ 1687 public final HttpClientBuilder httpClientBuilder() { 1688 if (httpClientBuilder == null) 1689 httpClientBuilder = createHttpClientBuilder(); 1690 return httpClientBuilder; 1691 } 1692 1693 /** 1694 * Creates an instance of an {@link HttpClientBuilder} to be used to create the {@link HttpClient}. 1695 * 1696 * <p> 1697 * Subclasses can override this method to provide their own client builder. 1698 * The builder can also be specified using the {@link #httpClientBuilder(HttpClientBuilder)} method. 1699 * 1700 * <h5 class='section'>Example:</h5> 1701 * <p class='bjava'> 1702 * <jc>// A Builder that provides it's own customized HttpClientBuilder.</jc> 1703 * <jk>public class</jk> MyBuilder <jk>extends</jk> Builder { 1704 * <ja>@Override</ja> 1705 * <jk>protected</jk> HttpClientBuilder createHttpClientBuilder() { 1706 * <jk>return</jk> HttpClientBuilder.<jsm>create</jsm>(); 1707 * } 1708 * } 1709 * 1710 * <jc>// Instantiate.</jc> 1711 * RestClient <jv>client</jv> = <jk>new</jk> MyBuilder().build(); 1712 * </p> 1713 * 1714 * @return The HTTP client builder to use to create the HTTP client. 1715 */ 1716 protected HttpClientBuilder createHttpClientBuilder() { 1717 return HttpClientBuilder.create(); 1718 } 1719 1720 /** 1721 * Sets the {@link HttpClientBuilder} that will be used to create the {@link HttpClient} used by {@link RestClient}. 1722 * 1723 * <p> 1724 * This can be used to bypass the builder created by {@link #createHttpClientBuilder()} method. 1725 * 1726 * <h5 class='section'>Example:</h5> 1727 * <p class='bjava'> 1728 * <jc>// Construct a client that uses a customized HttpClientBuilder.</jc> 1729 * RestClient <jv>client</jv> = RestClient 1730 * .<jsm>create</jsm>() 1731 * .httpClientBuilder(HttpClientBuilder.<jsm>create</jsm>()) 1732 * .build(); 1733 * </p> 1734 * 1735 * @param value The {@link HttpClientBuilder} that will be used to create the {@link HttpClient} used by {@link RestClient}. 1736 * @return This object. 1737 */ 1738 public Builder httpClientBuilder(HttpClientBuilder value) { 1739 this.httpClientBuilder = value; 1740 return this; 1741 } 1742 1743 //------------------------------------------------------------------------------------------------------------------ 1744 // httpClient 1745 //------------------------------------------------------------------------------------------------------------------ 1746 1747 /** 1748 * Creates an instance of an {@link HttpClient} to be used to handle all HTTP communications with the target server. 1749 * 1750 * <p> 1751 * This HTTP client is used when the HTTP client is not specified through one of the constructors or the 1752 * {@link #httpClient(CloseableHttpClient)} method. 1753 * 1754 * <p> 1755 * Subclasses can override this method to provide specially-configured HTTP clients to handle stuff such as 1756 * SSL/TLS certificate handling, authentication, etc. 1757 * 1758 * <p> 1759 * The default implementation returns an instance of {@link HttpClient} using the client builder returned by 1760 * {@link #createHttpClientBuilder()}. 1761 * 1762 * <h5 class='section'>Example:</h5> 1763 * <p class='bjava'> 1764 * <jc>// A Builder that provides it's own customized HttpClient.</jc> 1765 * <jk>public class</jk> MyBuilder <jk>extends</jk> Builder { 1766 * <ja>@Override</ja> 1767 * <jk>protected</jk> HttpClientBuilder createHttpClient() { 1768 * <jk>return</jk> HttpClientBuilder.<jsm>create</jsm>().build(); 1769 * } 1770 * } 1771 * 1772 * <jc>// Instantiate.</jc> 1773 * RestClient <jv>client</jv> = <jk>new</jk> MyBuilder().build(); 1774 * </p> 1775 * 1776 * @return The HTTP client to use. 1777 */ 1778 protected CloseableHttpClient createHttpClient() { 1779 if (connectionManager == null) 1780 connectionManager = createConnectionManager(); 1781 httpClientBuilder().setConnectionManager(connectionManager); 1782 return httpClientBuilder().build(); 1783 } 1784 1785 /** 1786 * Sets the {@link HttpClient} to be used to handle all HTTP communications with the target server. 1787 * 1788 * <p> 1789 * This can be used to bypass the client created by {@link #createHttpClient()} method. 1790 * 1791 * <h5 class='section'>Example:</h5> 1792 * <p class='bjava'> 1793 * <jc>// Construct a client that uses a customized HttpClient.</jc> 1794 * RestClient <jv>client</jv> = RestClient 1795 * .<jsm>create</jsm>() 1796 * .httpClient(HttpClientBuilder.<jsm>create</jsm>().build()) 1797 * .build(); 1798 * </p> 1799 * 1800 * @param value The {@link HttpClient} to be used to handle all HTTP communications with the target server. 1801 * @return This object. 1802 */ 1803 public Builder httpClient(CloseableHttpClient value) { 1804 this.httpClient = value; 1805 return this; 1806 } 1807 1808 final CloseableHttpClient getHttpClient() { 1809 return httpClient != null ? httpClient : createHttpClient(); 1810 } 1811 1812 //------------------------------------------------------------------------------------------------------------------ 1813 // serializers 1814 //------------------------------------------------------------------------------------------------------------------ 1815 1816 /** 1817 * Returns the serializer group sub-builder. 1818 * 1819 * @return The serializer group sub-builder. 1820 */ 1821 public final SerializerSet.Builder serializers() { 1822 if (serializers == null) 1823 serializers = createSerializers(); 1824 return serializers; 1825 } 1826 1827 /** 1828 * Instantiates the serializer group sub-builder. 1829 * 1830 * @return A new serializer group sub-builder. 1831 */ 1832 protected SerializerSet.Builder createSerializers() { 1833 return SerializerSet.create().beanContext(beanContext()); 1834 } 1835 1836 /** 1837 * Serializer. 1838 * 1839 * <p> 1840 * Associates the specified {@link Serializer Serializer} with the HTTP client. 1841 * 1842 * <p> 1843 * The serializer is used to serialize POJOs into the HTTP request body. 1844 * 1845 * <h5 class='section'>Notes:</h5><ul> 1846 * <li class='note'>When using this method that takes in a class, the serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or 1847 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1848 * </ul> 1849 * 1850 * <h5 class='section'>Example:</h5> 1851 * <p class='bjava'> 1852 * <jc>// Create a client that uses JSON transport for request bodies.</jc> 1853 * RestClient <jv>client</jv> = RestClient 1854 * .<jsm>create</jsm>() 1855 * .serializer(JsonSerializer.<jk>class</jk>) 1856 * .sortCollections() <jc>// Sort any collections being serialized.</jc> 1857 * .build(); 1858 * </p> 1859 * 1860 * @param value 1861 * The new value for this setting. 1862 * <br>The default is {@link JsonSerializer}. 1863 * @return This object. 1864 */ 1865 @SuppressWarnings("unchecked") 1866 public Builder serializer(Class<? extends Serializer> value) { 1867 return serializers(value); 1868 } 1869 1870 /** 1871 * Serializer. 1872 * 1873 * <p> 1874 * Associates the specified {@link Serializer Serializer} with the HTTP client. 1875 * 1876 * <p> 1877 * The serializer is used to serialize POJOs into the HTTP request body. 1878 * 1879 * <h5 class='section'>Notes:</h5><ul> 1880 * <li class='note'>When using this method that takes in a pre-instantiated serializer, the serializer property setters (e.g. {@link #sortCollections()}) or 1881 * bean context property setters (e.g. {@link #swaps(Class...)}) defined 1882 * on this builder class have no effect. 1883 * </ul> 1884 * 1885 * <h5 class='section'>Example:</h5> 1886 * <p class='bjava'> 1887 * <jc>// Create a client that uses a predefined JSON serializer request bodies.</jc> 1888 * RestClient <jv>client</jv> = RestClient 1889 * .<jsm>create</jsm>() 1890 * .serializer(JsonSerializer.<jsf>DEFAULT_READABLE</jsf>) 1891 * .build(); 1892 * </p> 1893 * 1894 * @param value 1895 * The new value for this setting. 1896 * <br>The default is {@link JsonSerializer}. 1897 * @return This object. 1898 */ 1899 public Builder serializer(Serializer value) { 1900 return serializers(value); 1901 } 1902 1903 /** 1904 * Serializers. 1905 * 1906 * <p> 1907 * Associates the specified {@link Serializer Serializers} with the HTTP client. 1908 * 1909 * <p> 1910 * The serializer is used to serialize POJOs into the HTTP request body. 1911 * 1912 * <p> 1913 * The serializer that best matches the <c>Content-Type</c> header will be used to serialize the request body. 1914 * <br>If no <c>Content-Type</c> header is specified, the first serializer in the list will be used. 1915 * 1916 * <h5 class='section'>Notes:</h5><ul> 1917 * <li class='note'>When using this method that takes in classes, the serializers can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or 1918 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 1919 * </ul> 1920 * 1921 * <h5 class='section'>Example:</h5> 1922 * <p class='bjava'> 1923 * <jc>// Create a client that uses JSON and XML transport for request bodies.</jc> 1924 * RestClient <jv>client</jv> = RestClient 1925 * .<jsm>create</jsm>() 1926 * .serializers(JsonSerializer.<jk>class</jk>, XmlSerializer.<jk>class</jk>) 1927 * .sortCollections() <jc>// Sort any collections being serialized.</jc> 1928 * .build(); 1929 * </p> 1930 * 1931 * @param value 1932 * The new value for this setting. 1933 * <br>The default is {@link JsonSerializer}. 1934 * @return This object. 1935 */ 1936 @SuppressWarnings("unchecked") 1937 public Builder serializers(Class<? extends Serializer>...value) { 1938 serializers().add(value); 1939 return this; 1940 } 1941 1942 /** 1943 * Serializers. 1944 * 1945 * <p> 1946 * Associates the specified {@link Serializer Serializers} with the HTTP client. 1947 * 1948 * <p> 1949 * The serializer is used to serialize POJOs into the HTTP request body. 1950 * 1951 * <p> 1952 * The serializer that best matches the <c>Content-Type</c> header will be used to serialize the request body. 1953 * <br>If no <c>Content-Type</c> header is specified, the first serializer in the list will be used. 1954 * 1955 * <h5 class='section'>Notes:</h5><ul> 1956 * <li class='note'>When using this method that takes in a pre-instantiated serializers, the serializer property setters (e.g. {@link #sortCollections()}) or 1957 * bean context property setters (e.g. {@link #swaps(Class...)}) defined 1958 * on this builder class have no effect. 1959 * </ul> 1960 * 1961 * <h5 class='section'>Example:</h5> 1962 * <p class='bjava'> 1963 * <jc>// Create a client that uses predefined JSON and XML serializers for request bodies.</jc> 1964 * RestClient <jv>client</jv> = RestClient 1965 * .<jsm>create</jsm>() 1966 * .serializers(JsonSerializer.<jsf>DEFAULT_READABLE</jsf>, XmlSerializer.<jsf>DEFAULT_READABLE</jsf>) 1967 * .build(); 1968 * </p> 1969 * 1970 * @param value 1971 * The new value for this setting. 1972 * <br>The default is {@link JsonSerializer}. 1973 * @return This object. 1974 */ 1975 public Builder serializers(Serializer...value) { 1976 serializers().add(value); 1977 return this; 1978 } 1979 1980 //------------------------------------------------------------------------------------------------------------------ 1981 // parsers 1982 //------------------------------------------------------------------------------------------------------------------ 1983 1984 /** 1985 * Returns the parser group sub-builder. 1986 * 1987 * @return The parser group sub-builder. 1988 */ 1989 public final ParserSet.Builder parsers() { 1990 if (parsers == null) 1991 parsers = createParsers(); 1992 return parsers; 1993 } 1994 1995 /** 1996 * Instantiates the parser group sub-builder. 1997 * 1998 * @return A new parser group sub-builder. 1999 */ 2000 protected ParserSet.Builder createParsers() { 2001 return ParserSet.create().beanContext(beanContext()); 2002 } 2003 2004 /** 2005 * Parser. 2006 * 2007 * <p> 2008 * Associates the specified {@link Parser Parser} with the HTTP client. 2009 * 2010 * <p> 2011 * The parser is used to parse the HTTP response body into a POJO. 2012 * 2013 * <h5 class='section'>Notes:</h5><ul> 2014 * <li class='note'>When using this method that takes in a class, the parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or 2015 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 2016 * </ul> 2017 * 2018 * <h5 class='section'>Example:</h5> 2019 * <p class='bjava'> 2020 * <jc>// Create a client that uses JSON transport for response bodies.</jc> 2021 * RestClient <jv>client</jv> = RestClient 2022 * .<jsm>create</jsm>() 2023 * .parser(JsonParser.<jk>class</jk>) 2024 * .strict() <jc>// Enable strict mode on JsonParser.</jc> 2025 * .build(); 2026 * </p> 2027 * 2028 * @param value 2029 * The new value for this setting. 2030 * <br>The default value is {@link JsonParser#DEFAULT}. 2031 * @return This object. 2032 */ 2033 @SuppressWarnings("unchecked") 2034 public Builder parser(Class<? extends Parser> value) { 2035 return parsers(value); 2036 } 2037 2038 /** 2039 * Parser. 2040 * 2041 * <p> 2042 * Associates the specified {@link Parser Parser} with the HTTP client. 2043 * 2044 * <p> 2045 * The parser is used to parse the HTTP response body into a POJO. 2046 * 2047 * <h5 class='section'>Notes:</h5><ul> 2048 * <li class='note'>When using this method that takes in a pre-instantiated parser, the parser property setters (e.g. {@link #strict()}) or 2049 * bean context property setters (e.g. {@link #swaps(Class...)}) defined 2050 * on this builder class have no effect. 2051 * </ul> 2052 * 2053 * <h5 class='section'>Example:</h5> 2054 * <p class='bjava'> 2055 * <jc>// Create a client that uses a predefined JSON parser for response bodies.</jc> 2056 * RestClient <jv>client</jv> = RestClient 2057 * .<jsm>create</jsm>() 2058 * .parser(JsonParser.<jsf>DEFAULT_STRICT</jsf>) 2059 * .build(); 2060 * </p> 2061 * 2062 * @param value 2063 * The new value for this setting. 2064 * <br>The default value is {@link JsonParser#DEFAULT}. 2065 * @return This object. 2066 */ 2067 public Builder parser(Parser value) { 2068 return parsers(value); 2069 } 2070 2071 /** 2072 * Parsers. 2073 * 2074 * <p> 2075 * Associates the specified {@link Parser Parsers} with the HTTP client. 2076 * 2077 * <p> 2078 * The parsers are used to parse the HTTP response body into a POJO. 2079 * 2080 * <p> 2081 * The parser that best matches the <c>Accept</c> header will be used to parse the response body. 2082 * <br>If no <c>Accept</c> header is specified, the first parser in the list will be used. 2083 * 2084 * <h5 class='section'>Notes:</h5><ul> 2085 * <li class='note'>When using this method that takes in classes, the parsers can be configured using any of the parser property setters (e.g. {@link #strict()}) or 2086 * bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class. 2087 * </ul> 2088 * 2089 * <h5 class='section'>Example:</h5> 2090 * <p class='bjava'> 2091 * <jc>// Create a client that uses JSON and XML transport for response bodies.</jc> 2092 * RestClient <jv>client</jv> = RestClient 2093 * .<jsm>create</jsm>() 2094 * .parser(JsonParser.<jk>class</jk>, XmlParser.<jk>class</jk>) 2095 * .strict() <jc>// Enable strict mode on parsers.</jc> 2096 * .build(); 2097 * </p> 2098 * 2099 * @param value 2100 * The new value for this setting. 2101 * <br>The default value is {@link JsonParser#DEFAULT}. 2102 * @return This object. 2103 */ 2104 @SuppressWarnings("unchecked") 2105 public Builder parsers(Class<? extends Parser>...value) { 2106 parsers().add(value); 2107 return this; 2108 } 2109 2110 /** 2111 * Parsers. 2112 * 2113 * <p> 2114 * Associates the specified {@link Parser Parsers} with the HTTP client. 2115 * 2116 * <p> 2117 * The parsers are used to parse the HTTP response body into a POJO. 2118 * 2119 * <p> 2120 * The parser that best matches the <c>Accept</c> header will be used to parse the response body. 2121 * <br>If no <c>Accept</c> header is specified, the first parser in the list will be used. 2122 * 2123 * <h5 class='section'>Notes:</h5><ul> 2124 * <li class='note'>When using this method that takes in pre-instantiated parsers, the parser property setters (e.g. {@link #strict()}) or 2125 * bean context property setters (e.g. {@link #swaps(Class...)}) defined 2126 * on this builder class have no effect. 2127 * </ul> 2128 * 2129 * <h5 class='section'>Example:</h5> 2130 * <p class='bjava'> 2131 * <jc>// Create a client that uses JSON and XML transport for response bodies.</jc> 2132 * RestClient <jv>client</jv> = RestClient 2133 * .<jsm>create</jsm>() 2134 * .parser(JsonParser.<jsf>DEFAULT_STRICT</jsf>, XmlParser.<jsf>DEFAULT</jsf>) 2135 * .build(); 2136 * </p> 2137 * 2138 * @param value 2139 * The new value for this setting. 2140 * <br>The default value is {@link JsonParser#DEFAULT}. 2141 * @return This object. 2142 */ 2143 public Builder parsers(Parser...value) { 2144 parsers().add(value); 2145 return this; 2146 } 2147 2148 //------------------------------------------------------------------------------------------------------------------ 2149 // partSerializer 2150 //------------------------------------------------------------------------------------------------------------------ 2151 2152 /** 2153 * Returns the part serializer sub-builder. 2154 * 2155 * @return The part serializer sub-builder. 2156 */ 2157 public final HttpPartSerializer.Creator partSerializer() { 2158 if (partSerializer == null) 2159 partSerializer = createPartSerializer(); 2160 return partSerializer; 2161 } 2162 2163 /** 2164 * Instantiates the part serializer sub-builder. 2165 * 2166 * @return A new part serializer sub-builder. 2167 */ 2168 protected HttpPartSerializer.Creator createPartSerializer() { 2169 return HttpPartSerializer.creator().type(OpenApiSerializer.class).beanContext(beanContext()); 2170 } 2171 2172 /** 2173 * Part serializer. 2174 * 2175 * <p> 2176 * The serializer to use for serializing POJOs in form data, query parameters, headers, and path variables. 2177 * 2178 * <p> 2179 * The default part serializer is {@link OpenApiSerializer} which allows for schema-driven marshalling. 2180 * 2181 * <h5 class='section'>Example:</h5> 2182 * <p class='bjava'> 2183 * <jc>// Create a client that uses UON format by default for outgoing HTTP parts.</jc> 2184 * RestClient <jv>client</jv> = RestClient 2185 * .<jsm>create</jsm>() 2186 * .partSerializer(UonSerializer.<jk>class</jk>) 2187 * .build(); 2188 * </p> 2189 * 2190 * @param value 2191 * The new value for this setting. 2192 * <br>The default value is {@link OpenApiSerializer}. 2193 * @return This object. 2194 */ 2195 public Builder partSerializer(Class<? extends HttpPartSerializer> value) { 2196 partSerializer().type(value); 2197 return this; 2198 } 2199 2200 /** 2201 * Part serializer. 2202 * 2203 * <p> 2204 * The serializer to use for serializing POJOs in form data, query parameters, headers, and path variables. 2205 * 2206 * <p> 2207 * The default part serializer is {@link OpenApiSerializer} which allows for schema-driven marshalling. 2208 * 2209 * <h5 class='section'>Example:</h5> 2210 * <p class='bjava'> 2211 * <jc>// Create a client that uses UON format by default for outgoing HTTP parts.</jc> 2212 * RestClient <jv>client</jv> = RestClient 2213 * .<jsm>create</jsm>() 2214 * .partSerializer(UonSerializer.<jsf>DEFAULT</jsf>) 2215 * .build(); 2216 * </p> 2217 * 2218 * @param value 2219 * The new value for this setting. 2220 * <br>The default value is {@link OpenApiSerializer}. 2221 * @return This object. 2222 */ 2223 public Builder partSerializer(HttpPartSerializer value) { 2224 partSerializer().impl(value); 2225 return this; 2226 } 2227 2228 //------------------------------------------------------------------------------------------------------------------ 2229 // partParser 2230 //------------------------------------------------------------------------------------------------------------------ 2231 2232 /** 2233 * Returns the part parser sub-builder. 2234 * 2235 * @return The part parser sub-builder. 2236 */ 2237 public final HttpPartParser.Creator partParser() { 2238 if (partParser == null) 2239 partParser = createPartParser(); 2240 return partParser; 2241 } 2242 2243 /** 2244 * Instantiates the part parser sub-builder. 2245 * 2246 * @return A new part parser sub-builder. 2247 */ 2248 protected HttpPartParser.Creator createPartParser() { 2249 return HttpPartParser.creator().type(OpenApiParser.class).beanContext(beanContext()); 2250 } 2251 2252 /** 2253 * Part parser. 2254 * 2255 * <p> 2256 * The parser to use for parsing POJOs from form data, query parameters, headers, and path variables. 2257 * 2258 * <p> 2259 * The default part parser is {@link OpenApiParser} which allows for schema-driven marshalling. 2260 * 2261 * <h5 class='section'>Example:</h5> 2262 * <p class='bjava'> 2263 * <jc>// Create a client that uses UON format by default for incoming HTTP parts.</jc> 2264 * RestClient <jv>client</jv> = RestClient 2265 * .<jsm>create</jsm>() 2266 * .partParser(UonParser.<jk>class</jk>) 2267 * .build(); 2268 * </p> 2269 * 2270 * @param value 2271 * The new value for this setting. 2272 * <br>The default value is {@link OpenApiParser}. 2273 * @return This object. 2274 */ 2275 public Builder partParser(Class<? extends HttpPartParser> value) { 2276 partParser().type(value); 2277 return this; 2278 } 2279 2280 /** 2281 * Part parser. 2282 * 2283 * <p> 2284 * The parser to use for parsing POJOs from form data, query parameters, headers, and path variables. 2285 * 2286 * <p> 2287 * The default part parser is {@link OpenApiParser} which allows for schema-driven marshalling. 2288 * 2289 * <h5 class='section'>Example:</h5> 2290 * <p class='bjava'> 2291 * <jc>// Create a client that uses UON format by default for incoming HTTP parts.</jc> 2292 * RestClient <jv>client</jv> = RestClient 2293 * .<jsm>create</jsm>() 2294 * .partParser(UonParser.<jsf>DEFAULT</jsf>) 2295 * .build(); 2296 * </p> 2297 * 2298 * @param value 2299 * The new value for this setting. 2300 * <br>The default value is {@link OpenApiParser}. 2301 * @return This object. 2302 */ 2303 public Builder partParser(HttpPartParser value) { 2304 partParser().impl(value); 2305 return this; 2306 } 2307 2308 //------------------------------------------------------------------------------------------------------------------ 2309 // urlEncodingSerializer 2310 //------------------------------------------------------------------------------------------------------------------ 2311 2312 /** 2313 * Returns the URL-encoding serializer sub-builder. 2314 * 2315 * @return The URL-encoding serializer sub-builder. 2316 */ 2317 public final UrlEncodingSerializer.Builder urlEncodingSerializer() { 2318 if (urlEncodingSerializer == null) 2319 urlEncodingSerializer = createUrlEncodingSerializer(); 2320 return urlEncodingSerializer; 2321 } 2322 2323 /** 2324 * Instantiates the URL-encoding serializer sub-builder. 2325 * 2326 * @return A new URL-encoding serializer sub-builder. 2327 */ 2328 protected UrlEncodingSerializer.Builder createUrlEncodingSerializer() { 2329 return UrlEncodingSerializer.create().beanContext(beanContext()); 2330 } 2331 2332 //------------------------------------------------------------------------------------------------------------------ 2333 // headerData 2334 //------------------------------------------------------------------------------------------------------------------ 2335 2336 /** 2337 * Returns the builder for the list of headers that get applied to all requests created by this builder. 2338 * 2339 * <p> 2340 * This is the primary method for accessing the request header list. 2341 * On first call, the builder is created via the method {@link #createHeaderData()}. 2342 * 2343 * <h5 class='section'>Example:</h5> 2344 * <p class='bjava'> 2345 * <jc>// Create a client that adds a "Foo: bar" header on every request.</jc> 2346 * RestClient.Builder <jv>builder</jv> = RestClient.<jsm>create</jsm>(); 2347 * <jv>builder</jv>.headerData().setDefault(<js>"Foo"</js>, <js>"bar"</js>)); 2348 * RestClient <jv>client</jv> = <jv>builder</jv>.build(); 2349 * </p> 2350 * 2351 * <p> 2352 * The following convenience methods are also provided for updating the headers: 2353 * <ul> 2354 * <li class='jm'>{@link #headers(Header...)} 2355 * <li class='jm'>{@link #headersDefault(Header...)} 2356 * <li class='jm'>{@link #header(String,String)} 2357 * <li class='jm'>{@link #header(String,Supplier)} 2358 * <li class='jm'>{@link #mediaType(String)} 2359 * <li class='jm'>{@link #mediaType(MediaType)} 2360 * <li class='jm'>{@link #accept(String)} 2361 * <li class='jm'>{@link #acceptCharset(String)} 2362 * <li class='jm'>{@link #clientVersion(String)} 2363 * <li class='jm'>{@link #contentType(String)} 2364 * <li class='jm'>{@link #debug()} 2365 * <li class='jm'>{@link #noTrace()} 2366 * </ul> 2367 * 2368 * @return The header list builder. 2369 */ 2370 public final HeaderList headers() { 2371 if (headerData == null) 2372 headerData = createHeaderData(); 2373 return headerData; 2374 } 2375 2376 /** 2377 * Creates the builder for the header list. 2378 * 2379 * <p> 2380 * Subclasses can override this method to provide their own implementation. 2381 * 2382 * <p> 2383 * The default behavior creates an empty builder. 2384 * 2385 * @return The header list builder. 2386 * @see #headers() 2387 */ 2388 protected HeaderList createHeaderData() { 2389 return HeaderList.create(); 2390 } 2391 2392 /** 2393 * Appends multiple headers to all requests. 2394 * 2395 * <h5 class='section'>Example:</h5> 2396 * <p class='bjava'> 2397 * <jk>import static</jk> org.apache.juneau.http.HttpHeaders.*; 2398 * 2399 * RestClient <jv>client</jv> = RestClient 2400 * .<jsm>create</jsm>() 2401 * .headers( 2402 * <jsf>ACCEPT_TEXT_XML</jsf>, 2403 * <jsm>stringHeader</jsm>(<js>"Foo"</js>, <js>"bar"</js>) 2404 * ) 2405 * .build(); 2406 * </p> 2407 * 2408 * <p> 2409 * This is a shortcut for calling <c>headerData().append(<jv>parts</jv>)</c>. 2410 * 2411 * @param parts 2412 * The header to set. 2413 * @return This object. 2414 * @see #headers() 2415 */ 2416 public Builder headers(Header...parts) { 2417 headers().append(parts); 2418 return this; 2419 } 2420 2421 /** 2422 * Sets default header values. 2423 * 2424 * <p> 2425 * Uses default values for specified headers if not otherwise specified on the outgoing requests. 2426 * 2427 * <h5 class='section'>Example:</h5> 2428 * <p class='bjava'> 2429 * RestClient <jv>client</jv> = RestClient 2430 * .<jsm>create</jsm>() 2431 * .headersDefault(<jsm>stringHeader</jsm>(<js>"Foo"</js>, ()-><js>"bar"</js>)); 2432 * .build(); 2433 * </p> 2434 * 2435 * <p> 2436 * This is a shortcut for calling <c>headerData().setDefault(<jv>parts</jv>)</c>. 2437 * 2438 * @param parts The header values. 2439 * @return This object. 2440 * @see #headers() 2441 */ 2442 public Builder headersDefault(Header...parts) { 2443 headers().setDefault(parts); 2444 return this; 2445 } 2446 2447 /** 2448 * Appends a header to all requests. 2449 * 2450 * <h5 class='section'>Example:</h5> 2451 * <p class='bjava'> 2452 * RestClient <jv>client</jv> = RestClient 2453 * .<jsm>create</jsm>() 2454 * .header(<js>"Foo"</js>, <js>"bar"</js>); 2455 * .build(); 2456 * </p> 2457 * 2458 * <p> 2459 * This is a shortcut for calling <c>headerData().append(<jv>name</jv>,<jv>value</jv>)</c>. 2460 * 2461 * @param name The header name. 2462 * @param value The header value. 2463 * @return This object. 2464 * @see #headers() 2465 */ 2466 public Builder header(String name, String value) { 2467 headers().append(name, value); 2468 return this; 2469 } 2470 2471 /** 2472 * Appends a header to all requests using a dynamic value. 2473 * 2474 * <h5 class='section'>Example:</h5> 2475 * <p class='bjava'> 2476 * RestClient <jv>client</jv> = RestClient 2477 * .<jsm>create</jsm>() 2478 * .header(<js>"Foo"</js>, ()-><js>"bar"</js>); 2479 * .build(); 2480 * </p> 2481 * 2482 * <p> 2483 * This is a shortcut for calling <c>headerData().append(<jv>name</jv>,<jv>value</jv>)</c>. 2484 * 2485 * @param name The header name. 2486 * @param value The header value supplier. 2487 * @return This object. 2488 * @see #headers() 2489 */ 2490 public Builder header(String name, Supplier<String> value) { 2491 headers().append(name, value); 2492 return this; 2493 } 2494 2495 /** 2496 * Appends the <c>Accept</c> and <c>Content-Type</c> headers on all requests made by this client. 2497 * 2498 * <p> 2499 * Headers are appended to the end of the current header list. 2500 * 2501 * <p> 2502 * This is a shortcut for calling <c>headerData().append(Accept.<jsm>of</jsm>(<jv>value</jv>), ContentType.<jsm>of</jsm>(<jv>value</jv>))</c>. 2503 * 2504 * @param value The new header values. 2505 * @return This object. 2506 * @see #headers() 2507 */ 2508 public Builder mediaType(String value) { 2509 super.mediaType(MediaType.of(value)); 2510 return headers(Accept.of(value), ContentType.of(value)); 2511 } 2512 2513 /** 2514 * Appends the <c>Accept</c> and <c>Content-Type</c> headers on all requests made by this client. 2515 * 2516 * <p> 2517 * Headers are appended to the end of the current header list. 2518 * 2519 * <p> 2520 * This is a shortcut for calling <c>headerData().append(Accept.<jsm>of</jsm>(<jv>value</jv>), ContentType.<jsm>of</jsm>(<jv>value</jv>))</c>. 2521 * 2522 * @param value The new header values. 2523 * @return This object. 2524 * @see #headers() 2525 */ 2526 @Override 2527 public Builder mediaType(MediaType value) { 2528 super.mediaType(value); 2529 return headers(Accept.of(value), ContentType.of(value)); 2530 } 2531 2532 /** 2533 * Appends an <c>Accept</c> header on this request. 2534 * 2535 * <p> 2536 * This is a shortcut for calling <c>headerData().append(Accept.<jsm>of</jsm>(<jv>value</jv>))</c>. 2537 * 2538 * @param value 2539 * The new header value. 2540 * @return This object. 2541 * @see #headers() 2542 */ 2543 public Builder accept(String value) { 2544 return headers(Accept.of(value)); 2545 } 2546 2547 /** 2548 * Sets the value for the <c>Accept-Charset</c> request header on all requests. 2549 * 2550 * <p> 2551 * This is a shortcut for calling <c>headerData().append(AcceptCharset.<jsm>of</jsm>(<jv>value</jv>))</c>. 2552 * 2553 * @param value The new header value. 2554 * @return This object. 2555 * @see #headers() 2556 */ 2557 public Builder acceptCharset(String value) { 2558 return headers(AcceptCharset.of(value)); 2559 } 2560 2561 /** 2562 * Sets the client version by setting the value for the <js>"Client-Version"</js> header. 2563 * 2564 * <p> 2565 * This is a shortcut for calling <c>headerData().append(ClientVersion.<jsm>of</jsm>(<jv>value</jv>))</c>. 2566 * 2567 * @param value The version string (e.g. <js>"1.2.3"</js>) 2568 * @return This object. 2569 * @see #headers() 2570 */ 2571 public Builder clientVersion(String value) { 2572 return headers(ClientVersion.of(value)); 2573 } 2574 2575 /** 2576 * Sets the value for the <c>Content-Type</c> request header on all requests. 2577 * 2578 * <p> 2579 * This is a shortcut for calling <c>headerData().append(ContentType.<jsm>of</jsm>(<jv>value</jv>))</c>. 2580 * 2581 * <p> 2582 * This overrides the media type specified on the serializer. 2583 * 2584 * @param value The new header value. 2585 * @return This object. 2586 * @see #headers() 2587 */ 2588 public Builder contentType(String value) { 2589 return headers(ContentType.of(value)); 2590 } 2591 2592 /** 2593 * Sets the value for the <c>Debug</c> request header on all requests. 2594 * 2595 * <p> 2596 * This is a shortcut for calling <c>headerData().append(Debug.<jsm>of</jsm>(<jv>value</jv>))</c>. 2597 * 2598 * @return This object. 2599 * @see #headers() 2600 */ 2601 @Override 2602 public Builder debug() { 2603 super.debug(); 2604 serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::debug); 2605 return headers(Debug.TRUE); 2606 } 2607 2608 /** 2609 * When called, <c>No-Trace: true</c> is added to requests. 2610 * 2611 * <p> 2612 * This gives the opportunity for the servlet to not log errors on invalid requests. 2613 * This is useful for testing purposes when you don't want your log file to show lots of errors that are simply the 2614 * results of testing. 2615 * 2616 * <p> 2617 * It's up to the server to decide whether to allow for this. 2618 * The <c>BasicTestRestLogger</c> class watches for this header and prevents logging of status 400+ responses to 2619 * prevent needless logging of test scenarios. 2620 * 2621 * @return This object. 2622 * @see #headers() 2623 */ 2624 public Builder noTrace() { 2625 return headers(NoTrace.of(true)); 2626 } 2627 2628 //------------------------------------------------------------------------------------------------------------------ 2629 // queryData 2630 //------------------------------------------------------------------------------------------------------------------ 2631 2632 /** 2633 * Returns the builder for the list of query parameters that get applied to all requests created by this builder. 2634 * 2635 * <p> 2636 * This is the primary method for accessing the query parameter list. 2637 * On first call, the builder is created via the method {@link #createQueryData()}. 2638 * 2639 * <h5 class='section'>Example:</h5> 2640 * <p class='bjava'> 2641 * <jc>// Create a client that adds a "foo=bar" query parameter on every request.</jc> 2642 * RestClient.Builder <jv>builder</jv> = RestClient.<jsm>create</jsm>(); 2643 * <jv>builder</jv>.queryData().setDefault(<js>"foo"</js>, <js>"bar"</js>)); 2644 * RestClient <jv>client</jv> = <jv>builder</jv>.build(); 2645 * </p> 2646 * 2647 * <p> 2648 * The following convenience methods are also provided for updating the parameters: 2649 * <ul> 2650 * <li class='jm'>{@link #queryData(NameValuePair...)} 2651 * <li class='jm'>{@link #queryDataDefault(NameValuePair...)} 2652 * <li class='jm'>{@link #queryData(String,String)} 2653 * <li class='jm'>{@link #queryData(String,Supplier)} 2654 * </ul> 2655 * 2656 * @return The query data list builder. 2657 */ 2658 public final PartList queryData() { 2659 if (queryData == null) 2660 queryData = createQueryData(); 2661 return queryData; 2662 } 2663 2664 /** 2665 * Creates the builder for the query data list. 2666 * 2667 * <p> 2668 * Subclasses can override this method to provide their own implementation. 2669 * 2670 * <p> 2671 * The default behavior creates an empty builder. 2672 * 2673 * @return The query data list builder. 2674 * @see #queryData() 2675 */ 2676 protected PartList createQueryData() { 2677 return PartList.create(); 2678 } 2679 2680 /** 2681 * Appends multiple query parameters to the URI of all requests. 2682 * 2683 * <h5 class='section'>Example:</h5> 2684 * <p class='bjava'> 2685 * <jk>import static</jk> org.apache.juneau.http.HttpParts.*; 2686 * 2687 * RestClient <jv>client</jv> = RestClient 2688 * .<jsm>create</jsm>() 2689 * .queryData( 2690 * <jsm>stringPart</jsm>(<js>"foo"</js>, <js>"bar"</js>), 2691 * <jsm>booleanPart</jsm>(<js>"baz"</js>, <jk>true</jk>) 2692 * ) 2693 * .build(); 2694 * </p> 2695 * 2696 * <p> 2697 * This is a shortcut for calling <c>queryData().append(<jv>parts</jv>)</c>. 2698 * 2699 * @param parts 2700 * The query parameters. 2701 * @return This object. 2702 * @see #queryData() 2703 */ 2704 public Builder queryData(NameValuePair...parts) { 2705 queryData().append(parts); 2706 return this; 2707 } 2708 2709 /** 2710 * Sets default query parameter values. 2711 * 2712 * <p> 2713 * Uses default values for specified parameters if not otherwise specified on the outgoing requests. 2714 * 2715 * <h5 class='section'>Example:</h5> 2716 * <p class='bjava'> 2717 * RestClient <jv>client</jv> = RestClient 2718 * .<jsm>create</jsm>() 2719 * .queryDataDefault(<jsm>stringPart</jsm>(<js>"foo"</js>, ()-><js>"bar"</js>)); 2720 * .build(); 2721 * </p> 2722 * 2723 * <p> 2724 * This is a shortcut for calling <c>queryData().setDefault(<jv>parts</jv>)</c>. 2725 * 2726 * @param parts The parts. 2727 * @return This object. 2728 * @see #queryData() 2729 */ 2730 public Builder queryDataDefault(NameValuePair...parts) { 2731 queryData().setDefault(parts); 2732 return this; 2733 } 2734 2735 /** 2736 * Appends a query parameter to the URI. 2737 * 2738 * <h5 class='section'>Example:</h5> 2739 * <p class='bjava'> 2740 * RestClient <jv>client</jv> = RestClient 2741 * .<jsm>create</jsm>() 2742 * .queryData(<js>"foo"</js>, <js>"bar"</js>) 2743 * .build(); 2744 * </p> 2745 * 2746 * <p> 2747 * This is a shortcut for calling <c>queryData().append(<jv>name</jv>,<jv>value</jv>)</c>. 2748 * 2749 * @param name The parameter name. 2750 * @param value The parameter value. 2751 * @return This object. 2752 * @see #queryData() 2753 */ 2754 public Builder queryData(String name, String value) { 2755 queryData().append(name, value); 2756 return this; 2757 } 2758 2759 /** 2760 * Appends a query parameter with a dynamic value to the URI. 2761 * 2762 * <h5 class='section'>Example:</h5> 2763 * <p class='bjava'> 2764 * RestClient <jv>client</jv> = RestClient 2765 * .<jsm>create</jsm>() 2766 * .queryData(<js>"foo"</js>, ()-><js>"bar"</js>) 2767 * .build(); 2768 * </p> 2769 * 2770 * <p> 2771 * This is a shortcut for calling <c>queryData().append(<jv>name</jv>,<jv>value</jv>)</c>. 2772 * 2773 * @param name The parameter name. 2774 * @param value The parameter value supplier. 2775 * @return This object. 2776 * @see #queryData() 2777 */ 2778 public Builder queryData(String name, Supplier<String> value) { 2779 queryData().append(name, value); 2780 return this; 2781 } 2782 2783 //------------------------------------------------------------------------------------------------------------------ 2784 // formData 2785 //------------------------------------------------------------------------------------------------------------------ 2786 2787 /** 2788 * Returns the builder for the list of form data parameters that get applied to all requests created by this builder. 2789 * 2790 * <p> 2791 * This is the primary method for accessing the form data parameter list. 2792 * On first call, the builder is created via the method {@link #createFormData()}. 2793 * 2794 * <h5 class='section'>Example:</h5> 2795 * <p class='bjava'> 2796 * <jc>// Create a client that adds a "foo=bar" form-data parameter on every request.</jc> 2797 * RestClient.Builder <jv>builder</jv> = RestClient.<jsm>create</jsm>(); 2798 * <jv>builder</jv>.formData().setDefault(<js>"foo"</js>, <js>"bar"</js>)); 2799 * RestClient <jv>client</jv> = <jv>builder</jv>.build(); 2800 * </p> 2801 * 2802 * <p> 2803 * The following convenience methods are also provided for updating the parameters: 2804 * <ul> 2805 * <li class='jm'>{@link #formData(NameValuePair...)} 2806 * <li class='jm'>{@link #formDataDefault(NameValuePair...)} 2807 * <li class='jm'>{@link #formData(String,String)} 2808 * <li class='jm'>{@link #formData(String,Supplier)} 2809 * </ul> 2810 * 2811 * @return The form data list builder. 2812 */ 2813 public final PartList formData() { 2814 if (formData == null) 2815 formData = createFormData(); 2816 return formData; 2817 } 2818 2819 /** 2820 * Creates the builder for the form data list. 2821 * 2822 * <p> 2823 * Subclasses can override this method to provide their own implementation. 2824 * 2825 * <p> 2826 * The default behavior creates an empty builder. 2827 * 2828 * @return The query data list builder. 2829 * @see #formData() 2830 */ 2831 protected PartList createFormData() { 2832 return PartList.create(); 2833 } 2834 2835 /** 2836 * Appends multiple form-data parameters to the request bodies of all URL-encoded form posts. 2837 * 2838 * <h5 class='section'>Example:</h5> 2839 * <p class='bjava'> 2840 * <jk>import static</jk> org.apache.juneau.http.HttpParts.*; 2841 * 2842 * RestClient <jv>client</jv> = RestClient 2843 * .<jsm>create</jsm>() 2844 * .formData( 2845 * <jsm>stringPart</jsm>(<js>"foo"</js>, <js>"bar"</js>), 2846 * <jsm>booleanPart</jsm>(<js>"baz"</js>, <jk>true</jk>) 2847 * ) 2848 * .build(); 2849 * </p> 2850 * 2851 * <p> 2852 * This is a shortcut for calling <c>formData().append(<jv>parts</jv>)</c>. 2853 * 2854 * @param parts 2855 * The form-data parameters. 2856 * @return This object. 2857 * @see #formData() 2858 */ 2859 public Builder formData(NameValuePair...parts) { 2860 formData().append(parts); 2861 return this; 2862 } 2863 2864 /** 2865 * Sets default form-data parameter values. 2866 * 2867 * <p> 2868 * Uses default values for specified parameters if not otherwise specified on the outgoing requests. 2869 * 2870 * <h5 class='section'>Example:</h5> 2871 * <p class='bjava'> 2872 * RestClient <jv>client</jv> = RestClient 2873 * .<jsm>create</jsm>() 2874 * .formDataDefault(<jsm>stringPart</jsm>(<js>"foo"</js>, ()-><js>"bar"</js>)); 2875 * .build(); 2876 * </p> 2877 * 2878 * <p> 2879 * This is a shortcut for calling <c>formData().setDefault(<jv>parts</jv>)</c>. 2880 * 2881 * @param parts The parts. 2882 * @return This object. 2883 * @see #formData() 2884 */ 2885 public Builder formDataDefault(NameValuePair...parts) { 2886 formData().setDefault(parts); 2887 return this; 2888 } 2889 2890 /** 2891 * Appends a form-data parameter to all request bodies. 2892 * 2893 * <h5 class='section'>Example:</h5> 2894 * <p class='bjava'> 2895 * RestClient <jv>client</jv> = RestClient 2896 * .<jsm>create</jsm>() 2897 * .formData(<js>"foo"</js>, <js>"bar"</js>) 2898 * .build(); 2899 * </p> 2900 * 2901 * <p> 2902 * This is a shortcut for calling <c>formData().append(<jv>name</jv>,<jv>value</jv>)</c>. 2903 * 2904 * @param name The parameter name. 2905 * @param value The parameter value. 2906 * @return This object. 2907 * @see #formData() 2908 */ 2909 public Builder formData(String name, String value) { 2910 formData().append(name, value); 2911 return this; 2912 } 2913 2914 /** 2915 * Appends a form-data parameter with a dynamic value to all request bodies. 2916 * 2917 * <h5 class='section'>Example:</h5> 2918 * <p class='bjava'> 2919 * RestClient <jv>client</jv> = RestClient 2920 * .<jsm>create</jsm>() 2921 * .formData(<js>"foo"</js>, ()-><js>"bar"</js>) 2922 * .build(); 2923 * </p> 2924 * 2925 * <p> 2926 * This is a shortcut for calling <c>formData().append(<jv>name</jv>,<jv>value</jv>)</c>. 2927 * 2928 * @param name The parameter name. 2929 * @param value The parameter value supplier. 2930 * @return This object. 2931 * @see #formData() 2932 */ 2933 public Builder formData(String name, Supplier<String> value) { 2934 formData().append(name, value); 2935 return this; 2936 } 2937 2938 //------------------------------------------------------------------------------------------------------------------ 2939 // pathData 2940 //------------------------------------------------------------------------------------------------------------------ 2941 2942 /** 2943 * Returns the builder for the list of path data parameters that get applied to all requests created by this builder. 2944 * 2945 * <p> 2946 * This is the primary method for accessing the path data parameter list. 2947 * On first call, the builder is created via the method {@link #createFormData()}. 2948 * 2949 * <h5 class='section'>Example:</h5> 2950 * <p class='bjava'> 2951 * <jc>// Create a client that uses "bar" for the "{foo}" path variable on every request.</jc> 2952 * RestClient.Builder <jv>builder</jv> = RestClient.<jsm>create</jsm>(); 2953 * <jv>builder</jv>.pathData().setDefault(<js>"foo"</js>, <js>"bar"</js>)); 2954 * RestClient <jv>client</jv> = <jv>builder</jv>.build(); 2955 * </p> 2956 * 2957 * <p> 2958 * The following convenience methods are also provided for updating the parameters: 2959 * <ul> 2960 * <li class='jm'>{@link #pathData(NameValuePair...)} 2961 * <li class='jm'>{@link #pathDataDefault(NameValuePair...)} 2962 * <li class='jm'>{@link #pathData(String,String)} 2963 * <li class='jm'>{@link #pathData(String,Supplier)} 2964 * </ul> 2965 * 2966 * @return The form data list builder. 2967 */ 2968 public final PartList pathData() { 2969 if (pathData == null) 2970 pathData = createPathData(); 2971 return pathData; 2972 } 2973 2974 /** 2975 * Creates the builder for the path data list. 2976 * 2977 * <p> 2978 * Subclasses can override this method to provide their own implementation. 2979 * 2980 * <p> 2981 * The default behavior creates an empty builder. 2982 * 2983 * @return The query data list builder. 2984 * @see #pathData() 2985 */ 2986 protected PartList createPathData() { 2987 return PartList.create(); 2988 } 2989 2990 /** 2991 * Sets multiple path parameters on all requests. 2992 * 2993 * <h5 class='section'>Example:</h5> 2994 * <p class='bjava'> 2995 * <jk>import static</jk> org.apache.juneau.http.HttpParts.*; 2996 * 2997 * RestClient <jv>client</jv> = RestClient 2998 * .<jsm>create</jsm>() 2999 * .pathData( 3000 * <jsm>stringPart</jsm>(<js>"foo"</js>, <js>"bar"</js>), 3001 * <jsm>booleanPart</jsm>(<js>"baz"</js>, <jk>true</jk>) 3002 * ) 3003 * .build(); 3004 * </p> 3005 * 3006 * <p> 3007 * This is a shortcut for calling <c>pathData().append(<jv>parts</jv>)</c>. 3008 * 3009 * @param parts 3010 * The path parameters. 3011 * @return This object. 3012 * @see #pathData() 3013 */ 3014 public Builder pathData(NameValuePair...parts) { 3015 pathData().append(parts); 3016 return this; 3017 } 3018 3019 /** 3020 * Sets default path parameter values. 3021 * 3022 * <p> 3023 * Uses default values for specified parameters if not otherwise specified on the outgoing requests. 3024 * 3025 * <h5 class='section'>Example:</h5> 3026 * <p class='bjava'> 3027 * RestClient <jv>client</jv> = RestClient 3028 * .<jsm>create</jsm>() 3029 * .pathDataDefault(<jsm>stringPart</jsm>(<js>"foo"</js>, ()-><js>"bar"</js>)); 3030 * .build(); 3031 * </p> 3032 * 3033 * <p> 3034 * This is a shortcut for calling <c>pathData().setDefault(<jv>parts</jv>)</c>. 3035 * 3036 * @param parts The parts. 3037 * @return This object. 3038 * @see #pathData() 3039 */ 3040 public Builder pathDataDefault(NameValuePair...parts) { 3041 pathData().setDefault(parts); 3042 return this; 3043 } 3044 3045 /** 3046 * Appends a path parameter to all request bodies. 3047 * 3048 * <h5 class='section'>Example:</h5> 3049 * <p class='bjava'> 3050 * RestClient <jv>client</jv> = RestClient 3051 * .<jsm>create</jsm>() 3052 * .pathData(<js>"foo"</js>, <js>"bar"</js>) 3053 * .build(); 3054 * </p> 3055 * 3056 * <p> 3057 * This is a shortcut for calling <c>pathData().append(<jv>name</jv>,<jv>value</jv>)</c>. 3058 * 3059 * @param name The parameter name. 3060 * @param value The parameter value. 3061 * @return This object. 3062 * @see #pathData() 3063 */ 3064 public Builder pathData(String name, String value) { 3065 pathData().append(name, value); 3066 return this; 3067 } 3068 3069 /** 3070 * Sets a path parameter with a dynamic value to all request bodies. 3071 * 3072 * <h5 class='section'>Example:</h5> 3073 * <p class='bjava'> 3074 * RestClient <jv>client</jv> = RestClient 3075 * .<jsm>create</jsm>() 3076 * .pathData(<js>"foo"</js>, ()-><js>"bar"</js>) 3077 * .build(); 3078 * </p> 3079 * 3080 * <p> 3081 * This is a shortcut for calling <c>pathData().append(<jv>name</jv>,<jv>value</jv>)</c>. 3082 * 3083 * @param name The parameter name. 3084 * @param value The parameter value supplier. 3085 * @return This object. 3086 * @see #pathData() 3087 */ 3088 public Builder pathData(String name, Supplier<String> value) { 3089 pathData().set(name, value); 3090 return this; 3091 } 3092 3093 //------------------------------------------------------------------------------------------------------------------ 3094 // callHandler 3095 //------------------------------------------------------------------------------------------------------------------ 3096 3097 /** 3098 * Returns the creator for the rest call handler. 3099 * 3100 * <p> 3101 * Allows you to provide a custom handler for making HTTP calls. 3102 * 3103 * <h5 class='section'>Example:</h5> 3104 * <p class='bjava'> 3105 * <jc>// Create a client that handles processing of requests using a custom handler.</jc> 3106 * <jk>public class</jk> MyRestCallHandler <jk>implements</jk> RestCallHandler { 3107 * 3108 * <ja>@Override</ja> 3109 * <jk>public</jk> HttpResponse run(HttpHost <jv>target</jv>, HttpRequest <jv>request</jv>, HttpContext <jv>context</jv>) <jk>throws</jk> IOException { 3110 * <jc>// Custom handle requests.</jc> 3111 * } 3112 * } 3113 * 3114 * RestClient <jv>client</jv> = RestClient 3115 * .<jsm>create</jsm>() 3116 * .callHandler(MyRestCallHandler.<jk>class</jk>) 3117 * .build(); 3118 * </p> 3119 * 3120 * <h5 class='section'>Notes:</h5><ul> 3121 * <li class='note'> 3122 * The {@link RestClient#run(HttpHost, HttpRequest, HttpContext)} method can also be overridden to produce the same results. 3123 * <li class='note'> 3124 * Use {@link BeanCreator#impl(Object)} to specify an already instantiated instance. 3125 * <li class='note'> 3126 * Use {@link BeanCreator#type(Class)} to specify a subtype to instantiate. 3127 * <br>Subclass must have a public constructor that takes in any args available 3128 * in the bean store of this builder (including {@link RestClient} itself). 3129 * </ul> 3130 * 3131 * <h5 class='section'>See Also:</h5><ul> 3132 * <li class='jic'>{@link RestCallHandler} 3133 * </ul> 3134 * 3135 * @return The creator for the rest call handler. 3136 */ 3137 public final BeanCreator<RestCallHandler> callHandler() { 3138 if (callHandler == null) 3139 callHandler = createCallHandler(); 3140 return callHandler; 3141 } 3142 3143 /** 3144 * Creates the creator for the rest call handler. 3145 * 3146 * <p> 3147 * Subclasses can override this method to provide their own implementation. 3148 * 3149 * <p> 3150 * The default behavior creates a bean creator initialized to return a {@link BasicRestCallHandler}. 3151 * 3152 * @return The creator for the rest call handler. 3153 * @see #callHandler() 3154 */ 3155 protected BeanCreator<RestCallHandler> createCallHandler() { 3156 return beanStore.createBean(RestCallHandler.class).type(BasicRestCallHandler.class); 3157 } 3158 3159 /** 3160 * REST call handler class. 3161 * 3162 * <p> 3163 * Specifies a custom handler for making HTTP calls. 3164 * 3165 * <p> 3166 * This is a shortcut for <c>callHandler().type(<jv>value</jv>)</c>. 3167 * 3168 * @param value 3169 * The new value for this setting. 3170 * @return This object. 3171 * @see #callHandler() 3172 */ 3173 public Builder callHandler(Class<? extends RestCallHandler> value) { 3174 callHandler().type(value); 3175 return this; 3176 } 3177 3178 //------------------------------------------------------------------------------------------------------------------ 3179 // errorCodes 3180 //------------------------------------------------------------------------------------------------------------------ 3181 3182 /** 3183 * Errors codes predicate. 3184 * 3185 * <p> 3186 * Defines a predicate to test for error codes. 3187 * 3188 * <h5 class='section'>Example:</h5> 3189 * <p class='bjava'> 3190 * <jc>// Create a client that considers any 300+ responses to be errors.</jc> 3191 * RestClient <jv>client</jv> = RestClient 3192 * .<jsm>create</jsm>() 3193 * .errorCodes(<jv>x</jv> -> <jv>x</jv>>=300) 3194 * .build(); 3195 * </p> 3196 * 3197 * @param value 3198 * The new value for this setting. 3199 * <br>The default value is <code>x -> x >= 400</code>. 3200 * @return This object. 3201 */ 3202 public Builder errorCodes(Predicate<Integer> value) { 3203 errorCodes = Utils.assertArgNotNull("value", value); 3204 return this; 3205 } 3206 3207 //------------------------------------------------------------------------------------------------------------------ 3208 // Logging. 3209 //------------------------------------------------------------------------------------------------------------------ 3210 3211 /** 3212 * Logger. 3213 * 3214 * <p> 3215 * Specifies the logger to use for logging. 3216 * 3217 * <p> 3218 * If not specified, uses the following logger: 3219 * <p class='bjava'> 3220 * Logger.<jsm>getLogger</jsm>(RestClient.<jk>class</jk>.getName()); 3221 * </p> 3222 * 3223 * <h5 class='section'>Example:</h5> 3224 * <p class='bjava'> 3225 * <jc>// Construct a client that logs messages to a special logger.</jc> 3226 * RestClient <jv>client</jv> = RestClient 3227 * .<jsm>create</jsm>() 3228 * .logger(Logger.<jsm>getLogger</jsm>(<js>"MyLogger"</js>)) <jc>// Log to MyLogger logger.</jc> 3229 * .logToConsole() <jc>// Also log to console.</jc> 3230 * .logRequests(<jsf>FULL</jsf>, <jsf>WARNING</jsf>) <jc>// Log requests with full detail at WARNING level.</jc> 3231 * .build(); 3232 * </p> 3233 * 3234 * @param value The logger to use for logging. 3235 * @return This object. 3236 */ 3237 public Builder logger(Logger value) { 3238 logger = value; 3239 return this; 3240 } 3241 3242 /** 3243 * Log to console. 3244 * 3245 * <p> 3246 * Specifies to log messages to the console. 3247 * 3248 * <h5 class='section'>Example:</h5> 3249 * <p class='bjava'> 3250 * <jc>// Construct a client that logs messages to a special logger.</jc> 3251 * RestClient <jv>client</jv> = RestClient 3252 * .<jsm>create</jsm>() 3253 * .logToConsole() 3254 * .logRequests(<jsf>FULL</jsf>, <jsf>INFO</jsf>) <jc>// Level is ignored when logging to console.</jc> 3255 * .build(); 3256 * </p> 3257 * 3258 * @return This object. 3259 */ 3260 public Builder logToConsole() { 3261 logToConsole = true; 3262 return this; 3263 } 3264 3265 /** 3266 * Log requests. 3267 * 3268 * <p> 3269 * Causes requests/responses to be logged at the specified log level at the end of the request. 3270 * 3271 * <p> 3272 * <jsf>SIMPLE</jsf> detail produces a log message like the following: 3273 * <p class='bconsole'> 3274 * POST http://localhost:10000/testUrl, HTTP/1.1 200 OK 3275 * </p> 3276 * 3277 * <p> 3278 * <jsf>FULL</jsf> detail produces a log message like the following: 3279 * <p class='bconsole'> 3280 * === HTTP Call (outgoing) ======================================================= 3281 * === REQUEST === 3282 * POST http://localhost:10000/testUrl 3283 * ---request headers--- 3284 * Debug: true 3285 * No-Trace: true 3286 * Accept: application/json 3287 * ---request entity--- 3288 * Content-Type: application/json 3289 * ---request content--- 3290 * {"foo":"bar","baz":123} 3291 * === RESPONSE === 3292 * HTTP/1.1 200 OK 3293 * ---response headers--- 3294 * Content-Type: application/json;charset=utf-8 3295 * Content-Length: 21 3296 * Server: Jetty(8.1.0.v20120127) 3297 * ---response content--- 3298 * {"message":"OK then"} 3299 * === END ======================================================================== 3300 * </p> 3301 * 3302 * <p> 3303 * By default, the message is logged to the default logger. It can be logged to a different logger via the 3304 * {@link #logger(Logger)} method or logged to the console using the 3305 * {@link #logToConsole()} method. 3306 * 3307 * @param detail The detail level of logging. 3308 * @param level The log level. 3309 * @param test A predicate to use per-request to see if the request should be logged. If <jk>null</jk>, always logs. 3310 * @return This object. 3311 */ 3312 public Builder logRequests(DetailLevel detail, Level level, BiPredicate<RestRequest,RestResponse> test) { 3313 logRequests = detail; 3314 logRequestsLevel = level; 3315 logRequestsPredicate = test; 3316 return this; 3317 } 3318 3319 //------------------------------------------------------------------------------------------------------------------ 3320 // HttpClientConnectionManager methods. 3321 //------------------------------------------------------------------------------------------------------------------ 3322 3323 /** 3324 * Creates the {@link HttpClientConnectionManager} returned by {@link #createConnectionManager()}. 3325 * 3326 * <p> 3327 * Subclasses can override this method to provide their own connection manager. 3328 * 3329 * <p> 3330 * The default implementation returns an instance of a {@link PoolingHttpClientConnectionManager} if {@link #pooled()} 3331 * was called or {@link BasicHttpClientConnectionManager} if not.. 3332 * 3333 * <h5 class='section'>Example:</h5> 3334 * <p class='bjava'> 3335 * <jc>// A Builder that provides it's own customized HttpClientConnectionManager.</jc> 3336 * <jk>public class</jk> MyBuilder <jk>extends</jk> Builder { 3337 * <ja>@Override</ja> 3338 * <jk>protected</jk> HttpClientConnectionManager createConnectionManager() { 3339 * <jk>return new</jk> PoolingHttpClientConnectionManager(); 3340 * } 3341 * } 3342 * 3343 * <jc>// Instantiate.</jc> 3344 * RestClient <jv>client</jv> = <jk>new</jk> MyBuilder().build(); 3345 * </p> 3346 * 3347 * @return The HTTP client builder to use to create the HTTP client. 3348 */ 3349 protected HttpClientConnectionManager createConnectionManager() { 3350 return (pooled ? new PoolingHttpClientConnectionManager() : new BasicHttpClientConnectionManager()); 3351 } 3352 3353 /** 3354 * When called, the {@link #createConnectionManager()} method will return a {@link PoolingHttpClientConnectionManager} 3355 * instead of a {@link BasicHttpClientConnectionManager}. 3356 * 3357 * <h5 class='section'>Example:</h5> 3358 * <p class='bjava'> 3359 * <jc>// Construct a client that uses pooled connections.</jc> 3360 * RestClient <jv>client</jv> = RestClient 3361 * .<jsm>create</jsm>() 3362 * .pooled() 3363 * .build(); 3364 * </p> 3365 * 3366 * @return This object. 3367 */ 3368 public Builder pooled() { 3369 this.pooled = true; 3370 return this; 3371 } 3372 3373 /** 3374 * Assigns {@link HttpClientConnectionManager} instance. 3375 * 3376 * @param value New property value. 3377 * @return This object. 3378 * @see HttpClientBuilder#setConnectionManager(HttpClientConnectionManager) 3379 */ 3380 public Builder connectionManager(HttpClientConnectionManager value) { 3381 connectionManager = value; 3382 httpClientBuilder().setConnectionManager(value); 3383 return this; 3384 } 3385 3386 /** 3387 * Defines the connection manager is to be shared by multiple client instances. 3388 * 3389 * <h5 class='section'>Notes:</h5><ul> 3390 * <li class='note'>If the connection manager is shared its life-cycle is expected to be managed by the caller and it will not be shut down if the client is closed. 3391 * </ul> 3392 * 3393 * @param shared New property value. 3394 * @return This object. 3395 * @see HttpClientBuilder#setConnectionManagerShared(boolean) 3396 */ 3397 public Builder connectionManagerShared(boolean shared) { 3398 httpClientBuilder().setConnectionManagerShared(shared); 3399 return this; 3400 } 3401 3402 /** 3403 * Set up this client to use BASIC auth. 3404 * 3405 * <h5 class='section'>Example:</h5> 3406 * <p class='bjava'> 3407 * <jc>// Construct a client that uses BASIC authentication.</jc> 3408 * RestClient <jv>client</jv> = RestClient 3409 * .<jsm>create</jsm>() 3410 * .basicAuth(<js>"http://localhost"</js>, 80, <js>"me"</js>, <js>"mypassword"</js>) 3411 * .build(); 3412 * </p> 3413 * 3414 * @param host The auth scope hostname. 3415 * @param port The auth scope port. 3416 * @param user The username. 3417 * @param pw The password. 3418 * @return This object. 3419 */ 3420 public Builder basicAuth(String host, int port, String user, String pw) { 3421 AuthScope scope = new AuthScope(host, port); 3422 Credentials up = new UsernamePasswordCredentials(user, pw); 3423 CredentialsProvider p = new BasicCredentialsProvider(); 3424 p.setCredentials(scope, up); 3425 defaultCredentialsProvider(p); 3426 return this; 3427 } 3428 3429 //----------------------------------------------------------------------------------------------------------------- 3430 // Properties 3431 //----------------------------------------------------------------------------------------------------------------- 3432 3433 /** 3434 * Console print stream 3435 * 3436 * <p> 3437 * Allows you to redirect the console output to a different print stream. 3438 * 3439 * @param value 3440 * The new value for this setting. 3441 * @return This object. 3442 */ 3443 public Builder console(PrintStream value) { 3444 console = value; 3445 return this; 3446 } 3447 3448 /** 3449 * <i><l>RestClient</l> configuration property: </i> Executor service. 3450 * 3451 * <p> 3452 * Defines the executor service to use when calling future methods on the {@link RestRequest} class. 3453 * 3454 * <p> 3455 * This executor service is used to create {@link Future} objects on the following methods: 3456 * <ul> 3457 * <li class='jm'>{@link RestRequest#runFuture()} 3458 * <li class='jm'>{@link RestRequest#completeFuture()} 3459 * <li class='jm'>{@link ResponseContent#asFuture(Class)} (and similar methods) 3460 * </ul> 3461 * 3462 * <p> 3463 * The default executor service is a single-threaded {@link ThreadPoolExecutor} with a 30 second timeout 3464 * and a queue size of 10. 3465 * 3466 * <h5 class='section'>Example:</h5> 3467 * <p class='bjava'> 3468 * <jc>// Create a client with a customized executor service.</jc> 3469 * RestClient <jv>client</jv> = RestClient 3470 * .<jsm>create</jsm>() 3471 * .executorService(<jk>new</jk> ThreadPoolExecutor(1, 1, 30, TimeUnit.<jsf>SECONDS</jsf>, <jk>new</jk> ArrayBlockingQueue<Runnable>(10)), <jk>true</jk>) 3472 * .build(); 3473 * 3474 * <jc>// Use it to asynchronously run a request.</jc> 3475 * Future<RestResponse> <jv>responseFuture</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).runFuture(); 3476 * 3477 * <jc>// Do some other stuff.</jc> 3478 * 3479 * <jc>// Now read the response.</jc> 3480 * String <jv>body</jv> = <jv>responseFuture</jv>.get().getContent().asString(); 3481 * 3482 * <jc>// Use it to asynchronously retrieve a response.</jc> 3483 * Future<MyBean> <jv>myBeanFuture</jv> = <jv>client</jv> 3484 * .get(<jsf>URI</jsf>) 3485 * .run() 3486 * .getContent().asFuture(MyBean.<jk>class</jk>); 3487 * 3488 * <jc>// Do some other stuff.</jc> 3489 * 3490 * <jc>// Now read the response.</jc> 3491 * MyBean <jv>bean</jv> = <jv>myBeanFuture</jv>.get(); 3492 * </p> 3493 * 3494 * @param executorService The executor service. 3495 * @param shutdownOnClose Call {@link ExecutorService#shutdown()} when {@link RestClient#close()} is called. 3496 * @return This object. 3497 */ 3498 public Builder executorService(ExecutorService executorService, boolean shutdownOnClose) { 3499 this.executorService = executorService; 3500 this.executorServiceShutdownOnClose = shutdownOnClose; 3501 return this; 3502 } 3503 3504 /** 3505 * <i><l>RestClient</l> configuration property: </i> Keep HttpClient open. 3506 * 3507 * <p> 3508 * Don't close this client when the {@link RestClient#close()} method is called. 3509 * 3510 * <h5 class='section'>Example:</h5> 3511 * <p class='bjava'> 3512 * <jc>// Create a client with a customized client and don't close the client service.</jc> 3513 * RestClient <jv>client</jv> = RestClient 3514 * .<jsm>create</jsm>() 3515 * .httpClient(<jv>myHttpClient</jv>) 3516 * .keepHttpClientOpen() 3517 * .build(); 3518 * 3519 * <jv>client</jv>.closeQuietly(); <jc>// Customized HttpClient won't be closed.</jc> 3520 * </p> 3521 * 3522 * @return This object. 3523 */ 3524 public Builder keepHttpClientOpen() { 3525 keepHttpClientOpen = true; 3526 return this; 3527 } 3528 3529 /** 3530 * Ignore errors. 3531 * 3532 * <p> 3533 * When enabled, HTTP error response codes (e.g. <l>>=400</l>) will not cause a {@link RestCallException} to 3534 * be thrown. 3535 * <p> 3536 * Note that this is equivalent to <c>builder.errorCodes(x -> <jk>false</jk>);</c> 3537 * 3538 * <h5 class='section'>Example:</h5> 3539 * <p class='bjava'> 3540 * <jc>// Create a client that doesn't throws a RestCallException when a 500 error occurs.</jc> 3541 * RestClient 3542 * .<jsm>create</jsm>() 3543 * .ignoreErrors() 3544 * .build() 3545 * .get(<js>"/error"</js>) <jc>// Throws a 500 error</jc> 3546 * .run() 3547 * .assertStatus().is(500); 3548 * </p> 3549 * 3550 * @return This object. 3551 */ 3552 public Builder ignoreErrors() { 3553 ignoreErrors = true; 3554 return this; 3555 } 3556 3557 /** 3558 * <i><l>RestClient</l> configuration property: </i> Call interceptors. 3559 * 3560 * <p> 3561 * Adds an interceptor that can be called to hook into specified events in the lifecycle of a single request. 3562 * 3563 * <h5 class='section'>Example:</h5> 3564 * <p class='bjava'> 3565 * <jc>// Customized interceptor (note you can also extend from BasicRestCallInterceptor as well.</jc> 3566 * <jk>public class</jk> MyRestCallInterceptor <jk>implements</jk> RestCallInterceptor { 3567 * 3568 * <ja>@Override</ja> 3569 * <jk>public void</jk> onInit(RestRequest <jv>req</jv>) <jk>throws</jk> Exception { 3570 * <jc>// Intercept immediately after RestRequest object is created and all headers/query/form-data has been 3571 * // set on the request from the client.</jc> 3572 * } 3573 * 3574 * <ja>@Override</ja> 3575 * <jk>public void</jk> onConnect(RestRequest <jv>req</jv>, RestResponse <jv>res</jv>) <jk>throws</jk> Exception { 3576 * <jc>// Intercept immediately after an HTTP response has been received.</jc> 3577 * } 3578 * 3579 * <ja>@Override</ja> 3580 * <jk>public void</jk> onClose(RestRequest <jv>req</jv>, RestResponse <jv>res</jv>) <jk>throws</jk> Exception { 3581 * <jc>// Intercept when the response body is consumed.</jc> 3582 * } 3583 * } 3584 * 3585 * <jc>// Create a client with a customized interceptor.</jc> 3586 * RestClient <jv>client</jv> = RestClient 3587 * .<jsm>create</jsm>() 3588 * .interceptors(MyRestCallInterceptor.<jk>class</jk>) 3589 * .build(); 3590 * </p> 3591 * 3592 * <h5 class='section'>Notes:</h5><ul> 3593 * <li class='note'>The {@link RestClient#onCallInit(RestRequest)}, {@link RestClient#onCallConnect(RestRequest,RestResponse)}, and 3594 * {@link RestClient#onCallClose(RestRequest,RestResponse)} methods can also be overridden to produce the same results. 3595 * </ul> 3596 * 3597 * @param values 3598 * The values to add to this setting. 3599 * <br>Can be implementations of any of the following: 3600 * <ul> 3601 * <li class='jic'>{@link RestCallInterceptor} 3602 * <li class='jic'>{@link HttpRequestInterceptor} 3603 * <li class='jic'>{@link HttpResponseInterceptor} 3604 * </ul> 3605 * @return This object. 3606 * @throws Exception If one or more interceptors could not be created. 3607 */ 3608 public Builder interceptors(Class<?>...values) throws Exception { 3609 for (Class<?> c : values) { 3610 ClassInfo ci = ClassInfo.of(c); 3611 if (ci != null) { 3612 if (ci.isChildOfAny(RestCallInterceptor.class, HttpRequestInterceptor.class, HttpResponseInterceptor.class)) 3613 interceptors(ci.newInstance()); 3614 else 3615 throw new ConfigException("Invalid class of type ''{0}'' passed to interceptors().", ci.getName()); 3616 } 3617 } 3618 return this; 3619 } 3620 3621 /** 3622 * Call interceptors. 3623 * 3624 * <p> 3625 * Adds an interceptor that gets called immediately after a connection is made. 3626 * 3627 * <h5 class='section'>Example:</h5> 3628 * <p class='bjava'> 3629 * <jc>// Create a client with a customized interceptor.</jc> 3630 * RestClient <jv>client</jv> = RestClient 3631 * .<jsm>create</jsm>() 3632 * .interceptors( 3633 * <jk>new</jk> RestCallInterceptor() { 3634 * 3635 * <ja>@Override</ja> 3636 * <jk>public void</jk> onInit(RestRequest <jv>req</jv>) <jk>throws</jk> Exception { 3637 * <jc>// Intercept immediately after RestRequest object is created and all headers/query/form-data has been 3638 * // set on the request from the client.</jc> 3639 * } 3640 * 3641 * <ja>@Override</ja> 3642 * <jk>public void</jk> onConnect(RestRequest <jv>req</jv>, RestResponse <jv>res</jv>) <jk>throws</jk> Exception { 3643 * <jc>// Intercept immediately after an HTTP response has been received.</jc> 3644 * } 3645 * 3646 * <ja>@Override</ja> 3647 * <jk>public void</jk> onClose(RestRequest <jv>req</jv>, RestResponse <jv>res</jv>) <jk>throws</jk> Exception { 3648 * <jc>// Intercept when the response body is consumed.</jc> 3649 * } 3650 * } 3651 * ) 3652 * .build(); 3653 * </p> 3654 * 3655 * <h5 class='section'>Notes:</h5><ul> 3656 * <li class='note'>The {@link RestClient#onCallInit(RestRequest)}, {@link RestClient#onCallConnect(RestRequest,RestResponse)}, and 3657 * {@link RestClient#onCallClose(RestRequest,RestResponse)} methods can also be overridden to produce the same results. 3658 * </ul> 3659 * 3660 * @param value 3661 * The values to add to this setting. 3662 * <br>Can be implementations of any of the following: 3663 * <ul> 3664 * <li class='jic'>{@link RestCallInterceptor} 3665 * <li class='jic'>{@link HttpRequestInterceptor} 3666 * <li class='jic'>{@link HttpResponseInterceptor} 3667 * </ul> 3668 * @return This object. 3669 */ 3670 public Builder interceptors(Object...value) { 3671 List<RestCallInterceptor> l = list(); 3672 for (Object o : value) { 3673 ClassInfo ci = ClassInfo.of(o); 3674 if (ci != null) { 3675 if (! ci.isChildOfAny(HttpRequestInterceptor.class, HttpResponseInterceptor.class, RestCallInterceptor.class)) 3676 throw new ConfigException("Invalid object of type ''{0}'' passed to interceptors().", ci.getName()); 3677 if (o instanceof HttpRequestInterceptor) 3678 addInterceptorLast((HttpRequestInterceptor)o); 3679 if (o instanceof HttpResponseInterceptor) 3680 addInterceptorLast((HttpResponseInterceptor)o); 3681 if (o instanceof RestCallInterceptor) 3682 l.add((RestCallInterceptor)o); 3683 } 3684 } 3685 if (interceptors == null) 3686 interceptors = l; 3687 else 3688 interceptors.addAll(0, l); 3689 return this; 3690 } 3691 3692 /** 3693 * <i><l>RestClient</l> configuration property: </i> Enable leak detection. 3694 * 3695 * <p> 3696 * Enable client and request/response leak detection. 3697 * 3698 * <p> 3699 * Causes messages to be logged to the console if clients or request/response objects are not properly closed 3700 * when the <c>finalize</c> methods are invoked. 3701 * 3702 * <p> 3703 * Automatically enabled with {@link org.apache.juneau.Context.Builder#debug()}. 3704 * 3705 * <h5 class='section'>Example:</h5> 3706 * <p class='bjava'> 3707 * <jc>// Create a client that logs a message if </jc> 3708 * RestClient <jv>client</jv> = RestClient 3709 * .<jsm>create</jsm>() 3710 * .detectLeaks() 3711 * .logToConsole() <jc>// Also log the error message to System.err</jc> 3712 * .build(); 3713 * 3714 * <jv>client</jv>.closeQuietly(); <jc>// Customized HttpClient won't be closed.</jc> 3715 * </p> 3716 * 3717 * @return This object. 3718 */ 3719 public Builder detectLeaks() { 3720 detectLeaks = true; 3721 return this; 3722 } 3723 3724 /** 3725 * <i><l>RestClient</l> configuration property: </i> Marshaller 3726 * 3727 * <p> 3728 * Shortcut for specifying the serializers and parsers 3729 * using the serializer and parser defined in a marshaller. 3730 * 3731 * <h5 class='section'>Notes:</h5><ul> 3732 * <li class='note'>When using this method that takes in a pre-instantiated serializers and parsers, the serializer property setters (e.g. {@link #sortCollections()}), 3733 * parser property setters (e.g. {@link #strict()}), or bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class have no effect. 3734 * </ul> 3735 * 3736 * <h5 class='section'>Example:</h5> 3737 * <p class='bjava'> 3738 * <jc>// Create a client that uses Simplified-JSON transport using an existing marshaller.</jc> 3739 * RestClient <jv>client</jv> = RestClient 3740 * .<jsm>create</jsm>() 3741 * .marshaller(Json5.<jsf>DEFAULT_READABLE</jsf>) 3742 * .build(); 3743 * </p> 3744 * 3745 * @param value The values to add to this setting. 3746 * @return This object. 3747 */ 3748 public Builder marshaller(Marshaller value) { 3749 if (value != null) 3750 serializer(value.getSerializer()).parser(value.getParser()); 3751 return this; 3752 } 3753 3754 /** 3755 * <i><l>RestClient</l> configuration property: </i> Marshalls 3756 * 3757 * <p> 3758 * Shortcut for specifying the serializers and parsers 3759 * using the serializer and parser defined in a marshaller. 3760 * 3761 * <h5 class='section'>Notes:</h5><ul> 3762 * <li class='note'>When using this method that takes in a pre-instantiated serializers and parsers, the serializer property setters (e.g. {@link #sortCollections()}), 3763 * parser property setters (e.g. {@link #strict()}), or bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class have no effect. 3764 * </ul> 3765 * 3766 * <h5 class='section'>Example:</h5> 3767 * <p class='bjava'> 3768 * <jc>// Create a client that uses JSON and XML transport using existing marshalls.</jc> 3769 * RestClient <jv>client</jv> = RestClient 3770 * .<jsm>create</jsm>() 3771 * .marshaller(Json.<jsf>DEFAULT_READABLE</jsf>, Xml.<jsf>DEFAULT_READABLE</jsf>) 3772 * .build(); 3773 * </p> 3774 * 3775 * @param value The values to add to this setting. 3776 * @return This object. 3777 */ 3778 public Builder marshallers(Marshaller...value) { 3779 for (Marshaller m : value) 3780 if (m != null) 3781 serializer(m.getSerializer()).parser(m.getParser()); 3782 return this; 3783 } 3784 3785 /** 3786 * <i><l>RestClient</l> configuration property: </i> Root URI. 3787 * 3788 * <p> 3789 * When set, relative URI strings passed in through the various rest call methods (e.g. {@link RestClient#get(Object)} 3790 * will be prefixed with the specified root. 3791 * <br>This root URI is ignored on those methods if you pass in a {@link URL}, {@link URI}, or an absolute URI string. 3792 * 3793 * <h5 class='section'>Example:</h5> 3794 * <p class='bjava'> 3795 * <jc>// Create a client that uses UON format by default for HTTP parts.</jc> 3796 * RestClient <jv>client</jv> = RestClient 3797 * .<jsm>create</jsm>() 3798 * .rootUrl(<js>"http://localhost:10000/foo"</js>) 3799 * .build(); 3800 * 3801 * Bar <jv>bar</jv> = <jv>client</jv> 3802 * .get(<js>"/bar"</js>) <jc>// Relative to http://localhost:10000/foo</jc> 3803 * .run() 3804 * .getContent().as(Bar.<jk>class</jk>); 3805 * </p> 3806 * 3807 * @param value 3808 * The root URI to prefix to relative URI strings. 3809 * <br>Trailing slashes are trimmed. 3810 * <br>Usually a <c>String</c> but you can also pass in <c>URI</c> and <c>URL</c> objects as well. 3811 * @return This object. 3812 */ 3813 public Builder rootUrl(Object value) { 3814 String s = s(value); 3815 if (! isEmpty(s)) 3816 s = s.replaceAll("\\/$", ""); 3817 if (isEmpty(s)) 3818 rootUrl = null; 3819 else if (s.indexOf("://") == -1) 3820 throw new BasicRuntimeException("Invalid rootUrl value: ''{0}''. Must be a valid absolute URL.", value); 3821 else 3822 rootUrl = s; 3823 return this; 3824 } 3825 3826 /** 3827 * Returns the root URI defined for this client. 3828 * 3829 * <p> 3830 * Returns <jk>null</jk> in leu of an empty string. 3831 * Trailing slashes are trimmed. 3832 * 3833 * @return The root URI defined for this client. 3834 */ 3835 public String getRootUri() { 3836 return rootUrl; 3837 } 3838 3839 /** 3840 * Skip empty form data. 3841 * 3842 * <p> 3843 * When enabled, form data consisting of empty strings will be skipped on requests. 3844 * Note that <jk>null</jk> values are already skipped. 3845 * 3846 * <p> 3847 * The {@link Schema#skipIfEmpty()} annotation overrides this setting. 3848 * 3849 * @param value 3850 * The new value for this setting. 3851 * <br>The default is <jk>false</jk>. 3852 * @return This object. 3853 */ 3854 public Builder skipEmptyFormData(boolean value) { 3855 skipEmptyFormData = true; 3856 return this; 3857 } 3858 3859 /** 3860 * Skip empty form data. 3861 * 3862 * <p> 3863 * When enabled, form data consisting of empty strings will be skipped on requests. 3864 * Note that <jk>null</jk> values are already skipped. 3865 * 3866 * <p> 3867 * The {@link Schema#skipIfEmpty()} annotation overrides this setting. 3868 * 3869 * @return This object. 3870 */ 3871 public Builder skipEmptyFormData() { 3872 return skipEmptyFormData(true); 3873 } 3874 3875 /** 3876 * Skip empty header data. 3877 * 3878 * <p> 3879 * When enabled, headers consisting of empty strings will be skipped on requests. 3880 * Note that <jk>null</jk> values are already skipped. 3881 * 3882 * <p> 3883 * The {@link Schema#skipIfEmpty()} annotation overrides this setting. 3884 * 3885 * @param value 3886 * The new value for this setting. 3887 * <br>The default is <jk>false</jk>. 3888 * @return This object. 3889 */ 3890 public Builder skipEmptyHeaderData(boolean value) { 3891 skipEmptyHeaderData = true; 3892 return this; 3893 } 3894 3895 /** 3896 * Skip empty header data. 3897 * 3898 * <p> 3899 * When enabled, headers consisting of empty strings will be skipped on requests. 3900 * Note that <jk>null</jk> values are already skipped. 3901 * 3902 * <p> 3903 * The {@link Schema#skipIfEmpty()} annotation overrides this setting. 3904 * 3905 * @return This object. 3906 */ 3907 public Builder skipEmptyHeaderData() { 3908 return skipEmptyHeaderData(true); 3909 } 3910 3911 /** 3912 * Skip empty query data. 3913 * 3914 * <p> 3915 * When enabled, query parameters consisting of empty strings will be skipped on requests. 3916 * Note that <jk>null</jk> values are already skipped. 3917 * 3918 * <p> 3919 * The {@link Schema#skipIfEmpty()} annotation overrides this setting. 3920 * 3921 * @param value 3922 * The new value for this setting. 3923 * <br>The default is <jk>false</jk>. 3924 * @return This object. 3925 */ 3926 public Builder skipEmptyQueryData(boolean value) { 3927 skipEmptyQueryData = true; 3928 return this; 3929 } 3930 3931 /** 3932 * Skip empty query data. 3933 * 3934 * <p> 3935 * When enabled, query parameters consisting of empty strings will be skipped on requests. 3936 * Note that <jk>null</jk> values are already skipped. 3937 * 3938 * <p> 3939 * The {@link Schema#skipIfEmpty()} annotation overrides this setting. 3940 * 3941 * @return This object. 3942 */ 3943 public Builder skipEmptyQueryData() { 3944 return skipEmptyQueryData(true); 3945 } 3946 3947 //----------------------------------------------------------------------------------------------------------------- 3948 // BeanTraverse Properties 3949 //----------------------------------------------------------------------------------------------------------------- 3950 3951 /** 3952 * <i><l>BeanTraverse</l> configuration property: </i> Automatically detect POJO recursions. 3953 * 3954 * <p> 3955 * When enabled, specifies that recursions should be checked for during traversal. 3956 * 3957 * <p> 3958 * Recursions can occur when traversing models that aren't true trees but rather contain loops. 3959 * <br>In general, unchecked recursions cause stack-overflow-errors. 3960 * <br>These show up as {@link BeanRecursionException BeanRecursionException} with the message <js>"Depth too deep. Stack overflow occurred."</js>. 3961 * 3962 * <h5 class='section'>Notes:</h5><ul> 3963 * <li class='note'> 3964 * Checking for recursion can cause a small performance penalty. 3965 * </ul> 3966 * 3967 * <h5 class='section'>Example:</h5> 3968 * <p class='bjava'> 3969 * <jc>// Create a JSON client that automatically checks for recursions.</jc> 3970 * RestClient <jv>client</jv> = RestClient 3971 * .<jsm>create</jsm>() 3972 * .json() 3973 * .detectRecursions() 3974 * .build(); 3975 * 3976 * <jc>// Create a POJO model with a recursive loop.</jc> 3977 * <jk>public class</jk> A { 3978 * <jk>public</jk> Object <jf>f</jf>; 3979 * } 3980 * A <jv>a</jv> = <jk>new</jk> A(); 3981 * <jv>a</jv>.<jf>f</jf> = <jv>a</jv>; 3982 * 3983 * <jk>try</jk> { 3984 * <jc>// Throws a RestCallException with an inner SerializeException and not a StackOverflowError</jc> 3985 * <jv>client</jv> 3986 * .post(<js>"http://localhost:10000/foo"</js>, <jv>a</jv>) 3987 * .run(); 3988 * } <jk>catch</jk> (RestCallException <jv>e</jv>} { 3989 * <jc>// Handle exception.</jc> 3990 * } 3991 * </p> 3992 * 3993 * <h5 class='section'>See Also:</h5><ul> 3994 * <li class='jm'>{@link org.apache.juneau.BeanTraverseContext.Builder#detectRecursions()} 3995 * </ul> 3996 * 3997 * @return This object. 3998 */ 3999 public Builder detectRecursions() { 4000 serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::detectRecursions); 4001 return this; 4002 } 4003 4004 /** 4005 * <i><l>BeanTraverse</l> configuration property: </i> Ignore recursion errors. 4006 * 4007 * <p> 4008 * When enabled, when we encounter the same object when traversing a tree, we set the value to <jk>null</jk>. 4009 * 4010 * <p> 4011 * For example, if a model contains the links A->B->C->A, then the JSON generated will look like 4012 * the following when <jsf>BEANTRAVERSE_ignoreRecursions</jsf> is <jk>true</jk>... 4013 * 4014 * <p class='bjson'> 4015 * {A:{B:{C:<jk>null</jk>}}} 4016 * </p> 4017 * 4018 * <h5 class='section'>Notes:</h5><ul> 4019 * <li class='note'> 4020 * Checking for recursion can cause a small performance penalty. 4021 * </ul> 4022 * 4023 * <h5 class='section'>Example:</h5> 4024 * <p class='bjava'> 4025 * <jc>// Create a JSON client that ignores recursions.</jc> 4026 * RestClient <jv>client</jv> = RestClient 4027 * .<jsm>create</jsm>() 4028 * .json() 4029 * .ignoreRecursions() 4030 * .build(); 4031 * 4032 * <jc>// Create a POJO model with a recursive loop.</jc> 4033 * <jk>public class</jk> A { 4034 * <jk>public</jk> Object <jf>f</jf>; 4035 * } 4036 * A <jv>a</jv> = <jk>new</jk> A(); 4037 * <jv>a</jv>.<jf>f</jf> = <jv>a</jv>; 4038 * 4039 * <jc>// Produces request body "{f:null}"</jc> 4040 * <jv>client</jv> 4041 * .post(<js>"http://localhost:10000/foo"</js>, <jv>a</jv>) 4042 * .run(); 4043 * </p> 4044 * 4045 * <h5 class='section'>See Also:</h5><ul> 4046 * <li class='jm'>{@link org.apache.juneau.BeanTraverseContext.Builder#ignoreRecursions()} 4047 * </ul> 4048 * 4049 * @return This object. 4050 */ 4051 public Builder ignoreRecursions() { 4052 serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::ignoreRecursions); 4053 return this; 4054 } 4055 4056 /** 4057 * <i><l>BeanTraverse</l> configuration property: </i> Initial depth. 4058 * 4059 * <p> 4060 * The initial indentation level at the root. 4061 * 4062 * <p> 4063 * Useful when constructing document fragments that need to be indented at a certain level when whitespace is enabled. 4064 * 4065 * <h5 class='section'>Example:</h5> 4066 * <p class='bjava'> 4067 * <jc>// Create a REST client with JSON serializer with whitespace enabled and an initial depth of 2.</jc> 4068 * RestClient <jv>client</jv> = RestClient 4069 * .<jsm>create</jsm>() 4070 * .json() 4071 * .ws() 4072 * .initialDepth(2) 4073 * .build(); 4074 * 4075 * <jc>// Our bean to serialize.</jc> 4076 * <jk>public class</jk> MyBean { 4077 * <jk>public</jk> String <jf>foo</jf> = <jk>null</jk>; 4078 * } 4079 * 4080 * <jc>// Produces request body "\t\t{\n\t\t\t'foo':'bar'\n\t\t}\n"</jc> 4081 * <jv>client</jv> 4082 * .post(<js>"http://localhost:10000/foo"</js>, <jk>new</jk> MyBean()) 4083 * .run(); 4084 * </p> 4085 * 4086 * <h5 class='section'>See Also:</h5><ul> 4087 * <li class='jm'>{@link org.apache.juneau.BeanTraverseContext.Builder#initialDepth(int)} 4088 * </ul> 4089 * 4090 * @param value 4091 * The new value for this property. 4092 * <br>The default is <c>0</c>. 4093 * @return This object. 4094 */ 4095 public Builder initialDepth(int value) { 4096 serializers().forEach(x -> x.initialDepth(value)); 4097 return this; 4098 } 4099 4100 /** 4101 * <i><l>BeanTraverse</l> configuration property: </i> Max serialization depth. 4102 * 4103 * <p> 4104 * When enabled, abort traversal if specified depth is reached in the POJO tree. 4105 * 4106 * <p> 4107 * If this depth is exceeded, an exception is thrown. 4108 * 4109 * <p> 4110 * This prevents stack overflows from occurring when trying to traverse models with recursive references. 4111 * 4112 * <h5 class='section'>Example:</h5> 4113 * <p class='bjava'> 4114 * <jc>// Create a REST client with JSON serializer that throws an exception if the depth reaches greater than 20.</jc> 4115 * RestClient <jv>client</jv> = RestClient 4116 * .<jsm>create</jsm>() 4117 * .json() 4118 * .maxDepth(20) 4119 * .build(); 4120 * </p> 4121 * 4122 * <h5 class='section'>See Also:</h5><ul> 4123 * <li class='jm'>{@link org.apache.juneau.BeanTraverseContext.Builder#maxDepth(int)} 4124 * </ul> 4125 * 4126 * @param value 4127 * The new value for this property. 4128 * <br>The default is <c>100</c>. 4129 * @return This object. 4130 */ 4131 public Builder maxDepth(int value) { 4132 serializers().forEach(x -> x.maxDepth(value)); 4133 return this; 4134 } 4135 4136 //----------------------------------------------------------------------------------------------------------------- 4137 // Serializer Properties 4138 //----------------------------------------------------------------------------------------------------------------- 4139 4140 /** 4141 * <i><l>Serializer</l> configuration property: </i> Add <js>"_type"</js> properties when needed. 4142 * 4143 * <p> 4144 * When enabled, <js>"_type"</js> properties will be added to beans if their type cannot be inferred 4145 * through reflection. 4146 * 4147 * <p> 4148 * This is used to recreate the correct objects during parsing if the object types cannot be inferred. 4149 * <br>For example, when serializing a <c>Map<String,Object></c> field where the bean class cannot be determined from 4150 * the type of the values. 4151 * 4152 * <p> 4153 * Note the differences between the following settings: 4154 * <ul class='javatree'> 4155 * <li class='jf'>{@link #addRootType()} - Affects whether <js>'_type'</js> is added to root node. 4156 * <li class='jf'>{@link #addBeanTypes()} - Affects whether <js>'_type'</js> is added to any nodes. 4157 * </ul> 4158 * 4159 * <h5 class='section'>Example:</h5> 4160 * <p class='bjava'> 4161 * <jc>// Create a JSON client that adds _type to nodes in the request body.</jc> 4162 * RestClient <jv>client</jv> = RestClient 4163 * .<jsm>create</jsm>() 4164 * .json() 4165 * .addBeanTypes() 4166 * .build(); 4167 * 4168 * <jc>// Our map of beans to serialize.</jc> 4169 * <ja>@Bean</ja>(typeName=<js>"mybean"</js>) 4170 * <jk>public class</jk> MyBean { 4171 * <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>; 4172 * } 4173 * 4174 * AMap <jv>map</jv> = AMap.of(<js>"foo"</js>, <jk>new</jk> MyBean()); 4175 * 4176 * <jc>// Request body will contain: {"foo":{"_type":"mybean","foo":"bar"}}</jc> 4177 * <jv>client</jv> 4178 * .post(<js>"http://localhost:10000/foo"</js>, <jv>map</jv>) 4179 * .run(); 4180 * </p> 4181 * 4182 * <h5 class='section'>See Also:</h5><ul> 4183 * <li class='jm'>{@link org.apache.juneau.serializer.Serializer.Builder#addBeanTypes()} 4184 * </ul> 4185 * 4186 * @return This object. 4187 */ 4188 public Builder addBeanTypes() { 4189 serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::addBeanTypes); 4190 return this; 4191 } 4192 4193 /** 4194 * <i><l>Serializer</l> configuration property: </i> Add type attribute to root nodes. 4195 * 4196 * <p> 4197 * When enabled, <js>"_type"</js> properties will be added to top-level beans. 4198 * 4199 * <p> 4200 * When disabled, it is assumed that the parser knows the exact Java POJO type being parsed, and therefore top-level 4201 * type information that might normally be included to determine the data type will not be serialized. 4202 * 4203 * <p> 4204 * For example, when serializing a top-level POJO with a {@link Bean#typeName() @Bean(typeName)} value, a 4205 * <js>'_type'</js> attribute will only be added when this setting is enabled. 4206 * 4207 * <p> 4208 * Note the differences between the following settings: 4209 * <ul class='javatree'> 4210 * <li class='jf'>{@link #addRootType()} - Affects whether <js>'_type'</js> is added to root node. 4211 * <li class='jf'>{@link #addBeanTypes()} - Affects whether <js>'_type'</js> is added to any nodes. 4212 * </ul> 4213 * 4214 * <h5 class='section'>Example:</h5> 4215 * <p class='bjava'> 4216 * <jc>// Create a JSON client that adds _type to root node.</jc> 4217 * RestClient <jv>client</jv> = RestClient 4218 * .<jsm>create</jsm>() 4219 * .json() 4220 * .addRootType() 4221 * .build(); 4222 * 4223 * <jc>// Our bean to serialize.</jc> 4224 * <ja>@Bean</ja>(typeName=<js>"mybean"</js>) 4225 * <jk>public class</jk> MyBean { 4226 * <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>; 4227 * } 4228 * 4229 * <jc>// Request body will contain: {"_type":"mybean","foo":"bar"}</jc> 4230 * <jv>client</jv> 4231 * .post(<js>"http://localhost:10000/foo"</js>, <jk>new</jk> MyBean()) 4232 * .run(); 4233 * </p> 4234 * 4235 * <h5 class='section'>See Also:</h5><ul> 4236 * <li class='jm'>{@link org.apache.juneau.serializer.Serializer.Builder#addRootType()} 4237 * </ul> 4238 * 4239 * @return This object. 4240 */ 4241 public Builder addRootType() { 4242 serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::addRootType); 4243 return this; 4244 } 4245 4246 /** 4247 * <i><l>Serializer</l> configuration property: </i> Don't trim null bean property values. 4248 * 4249 * <p> 4250 * When enabled, null bean values will be serialized to the output. 4251 * 4252 * <h5 class='section'>Notes:</h5><ul> 4253 * <li class='note'>Not enabling this setting will cause <c>Map</c>s with <jk>null</jk> values to be lost during parsing. 4254 * </ul> 4255 * 4256 * <h5 class='section'>Example:</h5> 4257 * <p class='bjava'> 4258 * <jc>// Create a REST client with JSON serializer that serializes null properties.</jc> 4259 * RestClient <jv>client</jv> = RestClient 4260 * .<jsm>create</jsm>() 4261 * .json() 4262 * .keepNullProperties() 4263 * .build(); 4264 * 4265 * <jc>// Our bean to serialize.</jc> 4266 * <jk>public class</jk> MyBean { 4267 * <jk>public</jk> String <jf>foo</jf> = <jk>null</jk>; 4268 * } 4269 * 4270 * <jc>// Request body will contain: {foo:null}</jc> 4271 * <jv>client</jv> 4272 * .post(<js>"http://localhost:10000/foo"</js>, <jk>new</jk> MyBean()) 4273 * .run(); 4274 * </p> 4275 * 4276 * <h5 class='section'>See Also:</h5><ul> 4277 * <li class='jm'>{@link org.apache.juneau.serializer.Serializer.Builder#keepNullProperties()} 4278 * </ul> 4279 * 4280 * @return This object. 4281 */ 4282 public Builder keepNullProperties() { 4283 serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::keepNullProperties); 4284 return this; 4285 } 4286 4287 /** 4288 * <i><l>Serializer</l> configuration property: </i> Sort arrays and collections alphabetically. 4289 * 4290 * <p> 4291 * When enabled, copies and sorts the contents of arrays and collections before serializing them. 4292 * 4293 * <p> 4294 * Note that this introduces a performance penalty since it requires copying the existing collection. 4295 * 4296 * <h5 class='section'>Example:</h5> 4297 * <p class='bjava'> 4298 * <jc>// Create a REST client with JSON serializer that sorts arrays and collections before serialization.</jc> 4299 * RestClient <jv>client</jv> = RestClient 4300 * .<jsm>create</jsm>() 4301 * .json() 4302 * .sortCollections() 4303 * .build(); 4304 * 4305 * <jc>// An unsorted array</jc> 4306 * String[] <jv>array</jv> = {<js>"foo"</js>,<js>"bar"</js>,<js>"baz"</js>} 4307 * 4308 * <jc>// Request body will contain: ["bar","baz","foo"]</jc> 4309 * <jv>client</jv> 4310 * .post(<js>"http://localhost:10000/foo"</js>, <jv>array</jv>) 4311 * .run(); 4312 * </p> 4313 * 4314 * <h5 class='section'>See Also:</h5><ul> 4315 * <li class='jm'>{@link org.apache.juneau.serializer.Serializer.Builder#sortCollections()} 4316 * </ul> 4317 * 4318 * @return This object. 4319 */ 4320 public Builder sortCollections() { 4321 serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::sortCollections); 4322 return this; 4323 } 4324 4325 /** 4326 * <i><l>Serializer</l> configuration property: </i> Sort maps alphabetically. 4327 * 4328 * <p> 4329 * When enabled, copies and sorts the contents of maps by their keys before serializing them. 4330 * 4331 * <p> 4332 * Note that this introduces a performance penalty. 4333 * 4334 * <h5 class='section'>Example:</h5> 4335 * <p class='bjava'> 4336 * <jc>// Create a REST client with JSON serializer that sorts maps before serialization.</jc> 4337 * RestClient <jv>client</jv> = RestClient 4338 * .<jsm>create</jsm>() 4339 * .json() 4340 * .sortMaps() 4341 * .build(); 4342 * 4343 * <jc>// An unsorted map.</jc> 4344 * AMap <jv>map</jv> = AMap.<jsm>of</jsm>(<js>"foo"</js>,1,<js>"bar"</js>,2,<js>"baz"</js>,3); 4345 * 4346 * <jc>// Request body will contain: {"bar":2,"baz":3,"foo":1}</jc> 4347 * <jv>client</jv> 4348 * .post(<js>"http://localhost:10000/foo"</js>, <jv>map</jv>) 4349 * .run(); 4350 * </p> 4351 * 4352 * <h5 class='section'>See Also:</h5><ul> 4353 * <li class='jm'>{@link org.apache.juneau.serializer.Serializer.Builder#sortMaps()} 4354 * </ul> 4355 * 4356 * @return This object. 4357 */ 4358 public Builder sortMaps() { 4359 serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::sortMaps); 4360 return this; 4361 } 4362 4363 /** 4364 * <i><l>Serializer</l> configuration property: </i> Trim empty lists and arrays. 4365 * 4366 * <p> 4367 * When enabled, empty lists and arrays will not be serialized. 4368 * 4369 * <p> 4370 * Note that enabling this setting has the following effects on parsing: 4371 * <ul class='spaced-list'> 4372 * <li> 4373 * Map entries with empty list values will be lost. 4374 * <li> 4375 * Bean properties with empty list values will not be set. 4376 * </ul> 4377 * 4378 * <h5 class='section'>Example:</h5> 4379 * <p class='bjava'> 4380 * <jc>// Create a serializer that skips empty arrays and collections.</jc> 4381 * WriterSerializer <jv>serializer</jv> = JsonSerializer 4382 * .<jsm>create</jsm>() 4383 * .trimEmptyCollections() 4384 * .build(); 4385 * 4386 * <jc>// A bean with a field with an empty array.</jc> 4387 * <jk>public class</jk> MyBean { 4388 * <jk>public</jk> String[] <jf>foo</jf> = {}; 4389 * } 4390 * 4391 * <jc>// Request body will contain: {}</jc> 4392 * <jv>client</jv> 4393 * .post(<js>"http://localhost:10000/foo"</js>, <jk>new</jk> MyBean()) 4394 * .run(); 4395 * </p> 4396 * 4397 * <h5 class='section'>See Also:</h5><ul> 4398 * <li class='jm'>{@link org.apache.juneau.serializer.Serializer.Builder#trimEmptyCollections()} 4399 * </ul> 4400 * 4401 * @return This object. 4402 */ 4403 public Builder trimEmptyCollections() { 4404 serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::trimEmptyCollections); 4405 return this; 4406 } 4407 4408 /** 4409 * <i><l>Serializer</l> configuration property: </i> Trim empty maps. 4410 * 4411 * <p> 4412 * When enabled, empty map values will not be serialized to the output. 4413 * 4414 * <p> 4415 * Note that enabling this setting has the following effects on parsing: 4416 * <ul class='spaced-list'> 4417 * <li> 4418 * Bean properties with empty map values will not be set. 4419 * </ul> 4420 * 4421 * <h5 class='section'>Example:</h5> 4422 * <p class='bjava'> 4423 * <jc>// Create a REST client with JSON serializer that skips empty maps.</jc> 4424 * RestClient <jv>client</jv> = RestClient 4425 * .<jsm>create</jsm>() 4426 * .json() 4427 * .trimEmptyMaps() 4428 * .build(); 4429 * 4430 * <jc>// A bean with a field with an empty map.</jc> 4431 * <jk>public class</jk> MyBean { 4432 * <jk>public</jk> AMap <jf>foo</jf> = AMap.<jsm>of</jsm>(); 4433 * } 4434 * 4435 * <jc>// Request body will contain: {}</jc> 4436 * <jv>client</jv> 4437 * .post(<js>"http://localhost:10000/foo"</js>, <jk>new</jk> MyBean()) 4438 * .run(); 4439 * </p> 4440 * 4441 * <h5 class='section'>See Also:</h5><ul> 4442 * <li class='jm'>{@link org.apache.juneau.serializer.Serializer.Builder#trimEmptyMaps()} 4443 * </ul> 4444 * 4445 * @return This object. 4446 */ 4447 public Builder trimEmptyMaps() { 4448 serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::trimEmptyMaps); 4449 return this; 4450 } 4451 4452 /** 4453 * <i><l>Serializer</l> configuration property: </i> Trim strings. 4454 * 4455 * <p> 4456 * When enabled, string values will be trimmed of whitespace using {@link String#trim()} before being serialized. 4457 * 4458 * <h5 class='section'>Example:</h5> 4459 * <p class='bjava'> 4460 * <jc>// Create a REST client with JSON serializer that trims strings before serialization.</jc> 4461 * RestClient <jv>client</jv> = RestClient 4462 * .<jsm>create</jsm>() 4463 * .json() 4464 * .trimStrings() 4465 * .build(); 4466 * 4467 * <jc>// A map with space-padded keys/values</jc> 4468 * AMap <jv>map</jv> = AMap.<jsm>of</jsm>(<js>" foo "</js>, <js>" bar "</js>); 4469 * 4470 * <jc>// Request body will contain: {"foo":"bar"}</jc> 4471 * <jv>client</jv> 4472 * .post(<js>"http://localhost:10000/foo"</js>, <jv>map</jv>) 4473 * .run(); 4474 * </p> 4475 * 4476 * <h5 class='section'>See Also:</h5><ul> 4477 * <li class='jm'>{@link org.apache.juneau.serializer.Serializer.Builder#trimStrings()} 4478 * </ul> 4479 * 4480 * @return This object. 4481 */ 4482 public Builder trimStringsOnWrite() { 4483 serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::trimStrings); 4484 return this; 4485 } 4486 4487 /** 4488 * <i><l>Serializer</l> configuration property: </i> URI context bean. 4489 * 4490 * <p> 4491 * Bean used for resolution of URIs to absolute or root-relative form. 4492 * 4493 * <h5 class='section'>Example:</h5> 4494 * <p class='bjava'> 4495 * <jc>// Our URI contextual information.</jc> 4496 * String <jv>authority</jv> = <js>"http://localhost:10000"</js>; 4497 * String <jv>contextRoot</jv> = <js>"/myContext"</js>; 4498 * String <jv>servletPath</jv> = <js>"/myServlet"</js>; 4499 * String <jv>pathInfo</jv> = <js>"/foo"</js>; 4500 * 4501 * <jc>// Create a UriContext object.</jc> 4502 * UriContext <jv>uriContext</jv> = <jk>new</jk> UriContext(<jv>authority</jv>, <jv>contextRoot</jv>, <jv>servletPath</jv>, <jv>pathInfo</jv>); 4503 * 4504 * <jc>// Create a REST client with JSON serializer and associate our context.</jc> 4505 * RestClient <jv>client</jv> = RestClient 4506 * .<jsm>create</jsm>() 4507 * .json() 4508 * .uriContext(<jv>uriContext</jv>) 4509 * .uriRelativity(<jsf>RESOURCE</jsf>) <jc>// Assume relative paths are relative to servlet.</jc> 4510 * .uriResolution(<jsf>ABSOLUTE</jsf>) <jc>// Serialize URIs as absolute paths.</jc> 4511 * .build(); 4512 * 4513 * <jc>// A relative URI</jc> 4514 * URI <jv>uri</jv> = <jk>new</jk> URI(<js>"bar"</js>); 4515 * 4516 * <jc>// Request body will contain: "http://localhost:10000/myContext/myServlet/foo/bar"</jc> 4517 * <jv>client</jv> 4518 * .post(<js>"http://localhost:10000/foo"</js>, <jv>uri</jv>) 4519 * .run(); 4520 * </p> 4521 * 4522 * <h5 class='section'>See Also:</h5><ul> 4523 * <li class='jm'>{@link org.apache.juneau.serializer.Serializer.Builder#uriContext(UriContext)} 4524 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/MarshallingUris">URIs</a> 4525 * </ul> 4526 * 4527 * @param value The new value for this property. 4528 * @return This object. 4529 */ 4530 public Builder uriContext(UriContext value) { 4531 serializers().forEach(x -> x.uriContext(value)); 4532 return this; 4533 } 4534 4535 /** 4536 * <i><l>Serializer</l> configuration property: </i> URI relativity. 4537 * 4538 * <p> 4539 * Defines what relative URIs are relative to when serializing any of the following: 4540 * <ul> 4541 * <li>{@link java.net.URI} 4542 * <li>{@link java.net.URL} 4543 * <li>Properties and classes annotated with {@link Uri @Uri} 4544 * </ul> 4545 * 4546 * <p> 4547 * See {@link #uriContext(UriContext)} for examples. 4548 * 4549 * <ul class='values javatree'> 4550 * <li class='jf'>{@link org.apache.juneau.UriRelativity#RESOURCE} 4551 * - Relative URIs should be considered relative to the servlet URI. 4552 * <li class='jf'>{@link org.apache.juneau.UriRelativity#PATH_INFO} 4553 * - Relative URIs should be considered relative to the request URI. 4554 * </ul> 4555 * 4556 * <h5 class='section'>See Also:</h5><ul> 4557 * <li class='jm'>{@link org.apache.juneau.serializer.Serializer.Builder#uriRelativity(UriRelativity)} 4558 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/MarshallingUris">URIs</a> 4559 * </ul> 4560 * 4561 * @param value 4562 * The new value for this property. 4563 * <br>The default is {@link UriRelativity#RESOURCE} 4564 * @return This object. 4565 */ 4566 public Builder uriRelativity(UriRelativity value) { 4567 serializers().forEach(x -> x.uriRelativity(value)); 4568 return this; 4569 } 4570 4571 /** 4572 * <i><l>Serializer</l> configuration property: </i> URI resolution. 4573 * 4574 * <p> 4575 * Defines the resolution level for URIs when serializing any of the following: 4576 * <ul> 4577 * <li>{@link java.net.URI} 4578 * <li>{@link java.net.URL} 4579 * <li>Properties and classes annotated with {@link Uri @Uri} 4580 * </ul> 4581 * 4582 * <p> 4583 * See {@link #uriContext(UriContext)} for examples. 4584 * 4585 * <ul class='values'> 4586 * <li class='jf'>{@link UriResolution#ABSOLUTE} 4587 * - Resolve to an absolute URI (e.g. <js>"http://host:port/context-root/servlet-path/path-info"</js>). 4588 * <li class='jf'>{@link UriResolution#ROOT_RELATIVE} 4589 * - Resolve to a root-relative URI (e.g. <js>"/context-root/servlet-path/path-info"</js>). 4590 * <li class='jf'>{@link UriResolution#NONE} 4591 * - Don't do any URI resolution. 4592 * </ul> 4593 * 4594 * <h5 class='section'>See Also:</h5><ul> 4595 * <li class='jm'>{@link org.apache.juneau.serializer.Serializer.Builder#uriResolution(UriResolution)} 4596 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/MarshallingUris">URIs</a> 4597 * </ul> 4598 * 4599 * @param value 4600 * The new value for this property. 4601 * <br>The default is {@link UriResolution#NONE} 4602 * @return This object. 4603 */ 4604 public Builder uriResolution(UriResolution value) { 4605 serializers().forEach(x -> x.uriResolution(value)); 4606 return this; 4607 } 4608 4609 //----------------------------------------------------------------------------------------------------------------- 4610 // WriterSerializer Properties 4611 //----------------------------------------------------------------------------------------------------------------- 4612 4613 /** 4614 * <i><l>WriterSerializer</l> configuration property: </i> Maximum indentation. 4615 * 4616 * <p> 4617 * Specifies the maximum indentation level in the serialized document. 4618 * 4619 * <h5 class='section'>Notes:</h5><ul> 4620 * <li class='note'>This setting does not apply to the RDF serializers. 4621 * </ul> 4622 * 4623 * <h5 class='section'>Example:</h5> 4624 * <p class='bjava'> 4625 * <jc>// Create a REST client with JSON serializer that indents a maximum of 20 tabs.</jc> 4626 * RestClient <jv>client</jv> = RestClient 4627 * .<jsm>create</jsm>() 4628 * .json() 4629 * .ws() <jc>// Enable whitespace</jc> 4630 * .maxIndent(20) 4631 * .build(); 4632 * </p> 4633 * 4634 * <h5 class='section'>See Also:</h5><ul> 4635 * <li class='jm'>{@link org.apache.juneau.serializer.WriterSerializer.Builder#maxIndent(int)} 4636 * </ul> 4637 * 4638 * @param value 4639 * The new value for this property. 4640 * <br>The default is <c>100</c>. 4641 * @return This object. 4642 */ 4643 public Builder maxIndent(int value) { 4644 serializers().forEachWS(x -> x.maxIndent(value)); 4645 return this; 4646 } 4647 4648 /** 4649 * <i><l>WriterSerializer</l> configuration property: </i> Quote character. 4650 * 4651 * <p> 4652 * Specifies the character to use for quoting attributes and values. 4653 * 4654 * <h5 class='section'>Notes:</h5><ul> 4655 * <li class='note'>This setting does not apply to the RDF serializers. 4656 * </ul> 4657 * 4658 * <h5 class='section'>Example:</h5> 4659 * <p class='bjava'> 4660 * <jc>// Create a REST client with JSON serializer that uses single quotes.</jc> 4661 * RestClient <jv>client</jv> = RestClient 4662 * .<jsm>create</jsm>() 4663 * .json() 4664 * .quoteChar(<js>'\''</js>) 4665 * .build(); 4666 * 4667 * <jc>// A bean with a single property</jc> 4668 * <jk>public class</jk> MyBean { 4669 * <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>; 4670 * } 4671 * 4672 * <jc>// Request body will contain: {'foo':'bar'}</jc> 4673 * <jv>client</jv> 4674 * .post(<js>"http://localhost:10000/foo"</js>, <jk>new</jk> MyBean()) 4675 * .run(); 4676 * </p> 4677 * 4678 * <h5 class='section'>See Also:</h5><ul> 4679 * <li class='jm'>{@link org.apache.juneau.serializer.WriterSerializer.Builder#quoteChar(char)} 4680 * </ul> 4681 * 4682 * @param value 4683 * The new value for this property. 4684 * <br>The default is <js>'"'</js>. 4685 * @return This object. 4686 */ 4687 public Builder quoteChar(char value) { 4688 serializers().forEachWS(x -> x.quoteChar(value)); 4689 return this; 4690 } 4691 4692 /** 4693 * <i><l>WriterSerializer</l> configuration property: </i> Quote character. 4694 * 4695 * <p> 4696 * Specifies to use single quotes for quoting attributes and values. 4697 * 4698 * <h5 class='section'>Notes:</h5><ul> 4699 * <li class='note'>This setting does not apply to the RDF serializers. 4700 * </ul> 4701 * 4702 * <h5 class='section'>Example:</h5> 4703 * <p class='bjava'> 4704 * <jc>// Create a REST client with JSON serializer that uses single quotes.</jc> 4705 * RestClient <jv>client</jv> = RestClient 4706 * .<jsm>create</jsm>() 4707 * .json() 4708 * .sq() 4709 * .build(); 4710 * 4711 * <jc>// A bean with a single property</jc> 4712 * <jk>public class</jk> MyBean { 4713 * <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>; 4714 * } 4715 * 4716 * <jc>// Request body will contain: {'foo':'bar'}</jc> 4717 * <jv>client</jv> 4718 * .post(<js>"http://localhost:10000/foo"</js>, <jk>new</jk> MyBean()) 4719 * .run(); 4720 * </p> 4721 * 4722 * <h5 class='section'>See Also:</h5><ul> 4723 * <li class='jm'>{@link org.apache.juneau.serializer.WriterSerializer.Builder#quoteChar(char)} 4724 * </ul> 4725 * 4726 * @return This object. 4727 */ 4728 public Builder sq() { 4729 serializers().forEachWS(org.apache.juneau.serializer.WriterSerializer.Builder::sq); 4730 return this; 4731 } 4732 4733 /** 4734 * <i><l>WriterSerializer</l> configuration property: </i> Use whitespace. 4735 * 4736 * <p> 4737 * When enabled, whitespace is added to the output to improve readability. 4738 * 4739 * <h5 class='section'>Example:</h5> 4740 * <p class='bjava'> 4741 * <jc>// Create a REST client with JSON serializer with whitespace enabled.</jc> 4742 * RestClient <jv>client</jv> = RestClient 4743 * .<jsm>create</jsm>() 4744 * .json() 4745 * .useWhitespace() 4746 * .build(); 4747 * 4748 * <jc>// A bean with a single property</jc> 4749 * <jk>public class</jk> MyBean { 4750 * <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>; 4751 * } 4752 * 4753 * <jc>// Request body will contain: {\n\t"foo": "bar"\n\}\n</jc> 4754 * <jv>client</jv> 4755 * .post(<js>"http://localhost:10000/foo"</js>, <jk>new</jk> MyBean()) 4756 * .run(); 4757 * </p> 4758 * 4759 * <h5 class='section'>See Also:</h5><ul> 4760 * <li class='jm'>{@link org.apache.juneau.serializer.WriterSerializer.Builder#useWhitespace()} 4761 * </ul> 4762 * @return This object. 4763 */ 4764 public Builder useWhitespace() { 4765 serializers().forEachWS(org.apache.juneau.serializer.WriterSerializer.Builder::useWhitespace); 4766 return this; 4767 } 4768 4769 /** 4770 * <i><l>WriterSerializer</l> configuration property: </i> Use whitespace. 4771 * 4772 * <p> 4773 * When enabled, whitespace is added to the output to improve readability. 4774 * 4775 * <h5 class='section'>Example:</h5> 4776 * <p class='bjava'> 4777 * <jc>// Create a REST client with JSON serializer with whitespace enabled.</jc> 4778 * RestClient <jv>client</jv> = RestClient 4779 * .<jsm>create</jsm>() 4780 * .json() 4781 * .ws() 4782 * .build(); 4783 * 4784 * <jc>// A bean with a single property</jc> 4785 * <jk>public class</jk> MyBean { 4786 * <jk>public</jk> String <jf>foo</jf> = <js>"bar"</js>; 4787 * } 4788 * 4789 * <jc>// Request body will contain: {\n\t"foo": "bar"\n\}\n</jc> 4790 * <jv>client</jv> 4791 * .post(<js>"http://localhost:10000/foo"</js>, <jk>new</jk> MyBean()) 4792 * .run(); 4793 * </p> 4794 * 4795 * <h5 class='section'>See Also:</h5><ul> 4796 * <li class='jm'>{@link org.apache.juneau.serializer.WriterSerializer.Builder#useWhitespace()} 4797 * </ul> 4798 * 4799 * @return This object. 4800 */ 4801 public Builder ws() { 4802 serializers().forEachWS(org.apache.juneau.serializer.WriterSerializer.Builder::ws); 4803 return this; 4804 } 4805 4806 //----------------------------------------------------------------------------------------------------------------- 4807 // OutputStreamSerializer Properties 4808 //----------------------------------------------------------------------------------------------------------------- 4809 4810 //----------------------------------------------------------------------------------------------------------------- 4811 // Parser Properties 4812 //----------------------------------------------------------------------------------------------------------------- 4813 4814 /** 4815 * <i><l>Parser</l> configuration property: </i> Debug output lines. 4816 * 4817 * <p> 4818 * When parse errors occur, this specifies the number of lines of input before and after the 4819 * error location to be printed as part of the exception message. 4820 * 4821 * <h5 class='section'>Example:</h5> 4822 * <p class='bjava'> 4823 * <jc>// Create a parser whose exceptions print out 100 lines before and after the parse error location.</jc> 4824 * RestClient <jv>client</jv> = RestClient 4825 * .<jsm>create</jsm>() 4826 * .json() 4827 * .debug() <jc>// Enable debug mode to capture Reader contents as strings.</jc> 4828 * .debugOuputLines(100) 4829 * .build(); 4830 * 4831 * <jc>// Try to parse some bad JSON.</jc> 4832 * <jk>try</jk> { 4833 * <jv>client</jv> 4834 * .get(<js>"/pathToBadJson"</js>) 4835 * .run() 4836 * .getContent().as(Object.<jk>class</jk>); <jc>// Try to parse it.</jc> 4837 * } <jk>catch</jk> (RestCallException <jv>e</jv>) { 4838 * System.<jsf>err</jsf>.println(<jv>e</jv>.getMessage()); <jc>// Will display 200 lines of the output.</jc> 4839 * } 4840 * </p> 4841 * 4842 * <h5 class='section'>See Also:</h5><ul> 4843 * <li class='jm'>{@link org.apache.juneau.parser.Parser.Builder#debugOutputLines(int)} 4844 * </ul> 4845 * 4846 * @param value 4847 * The new value for this property. 4848 * <br>The default value is <c>5</c>. 4849 * @return This object. 4850 */ 4851 public Builder debugOutputLines(int value) { 4852 parsers().forEach(x -> x.debugOutputLines(value)); 4853 return this; 4854 } 4855 4856 /** 4857 * <i><l>Parser</l> configuration property: </i> Strict mode. 4858 * 4859 * <p> 4860 * When enabled, strict mode for the parser is enabled. 4861 * 4862 * <p> 4863 * Strict mode can mean different things for different parsers. 4864 * 4865 * <table class='styled'> 4866 * <tr><th>Parser class</th><th>Strict behavior</th></tr> 4867 * <tr> 4868 * <td>All reader-based parsers</td> 4869 * <td> 4870 * When enabled, throws {@link ParseException ParseExceptions} on malformed charset input. 4871 * Otherwise, malformed input is ignored. 4872 * </td> 4873 * </tr> 4874 * <tr> 4875 * <td>{@link JsonParser}</td> 4876 * <td> 4877 * When enabled, throws exceptions on the following invalid JSON syntax: 4878 * <ul> 4879 * <li>Unquoted attributes. 4880 * <li>Missing attribute values. 4881 * <li>Concatenated strings. 4882 * <li>Javascript comments. 4883 * <li>Numbers and booleans when Strings are expected. 4884 * <li>Numbers valid in Java but not JSON (e.g. octal notation, etc...) 4885 * </ul> 4886 * </td> 4887 * </tr> 4888 * </table> 4889 * 4890 * <h5 class='section'>Example:</h5> 4891 * <p class='bjava'> 4892 * <jc>// Create a REST client with JSON parser using strict mode.</jc> 4893 * RestClient <jv>client</jv> = RestClient 4894 * .<jsm>create</jsm>() 4895 * .json() 4896 * .strict() 4897 * .build(); 4898 * 4899 * <jc>// Try to parse some bad JSON.</jc> 4900 * <jk>try</jk> { 4901 * <jv>client</jv> 4902 * .get(<js>"/pathToBadJson"</js>) 4903 * .run() 4904 * .getContent().as(Object.<jk>class</jk>); <jc>// Try to parse it.</jc> 4905 * } <jk>catch</jk> (RestCallException <jv>e</jv>) { 4906 * <jc>// Handle exception.</jc> 4907 * } 4908 * </p> 4909 * 4910 * <h5 class='section'>See Also:</h5><ul> 4911 * <li class='jm'>{@link org.apache.juneau.parser.Parser.Builder#strict()} 4912 * </ul> 4913 * 4914 * @return This object. 4915 */ 4916 public Builder strict() { 4917 parsers().forEach(org.apache.juneau.parser.Parser.Builder::strict); 4918 return this; 4919 } 4920 4921 /** 4922 * <i><l>Parser</l> configuration property: </i> Trim parsed strings. 4923 * 4924 * <p> 4925 * When enabled, string values will be trimmed of whitespace using {@link String#trim()} before being added to 4926 * the POJO. 4927 * 4928 * <h5 class='section'>Example:</h5> 4929 * <p class='bjava'> 4930 * <jc>// Create a REST client with JSON parser with trim-strings enabled.</jc> 4931 * RestClient <jv>client</jv> = RestClient 4932 * .<jsm>create</jsm>() 4933 * .json() 4934 * .trimStringsOnRead() 4935 * .build(); 4936 * 4937 * <jc>// Try to parse JSON containing {" foo ":" bar "}.</jc> 4938 * Map<String,String> <jv>map</jv> = <jv>client</jv> 4939 * .get(<js>"/pathToJson"</js>) 4940 * .run() 4941 * .getContent().as(HashMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>); 4942 * 4943 * <jc>// Make sure strings are trimmed.</jc> 4944 * <jsm>assertEquals</jsm>(<js>"bar"</js>, <jv>map</jv>.get(<js>"foo"</js>)); 4945 * </p> 4946 * 4947 * <h5 class='section'>See Also:</h5><ul> 4948 * <li class='jm'>{@link org.apache.juneau.parser.Parser.Builder#trimStrings()} 4949 * </ul> 4950 * 4951 * @return This object. 4952 */ 4953 public Builder trimStringsOnRead() { 4954 parsers().forEach(org.apache.juneau.parser.Parser.Builder::trimStrings); 4955 return this; 4956 } 4957 4958 //----------------------------------------------------------------------------------------------------------------- 4959 // ReaderParser Properties 4960 //----------------------------------------------------------------------------------------------------------------- 4961 4962 //----------------------------------------------------------------------------------------------------------------- 4963 // InputStreamParser Properties 4964 //----------------------------------------------------------------------------------------------------------------- 4965 4966 //----------------------------------------------------------------------------------------------------------------- 4967 // OpenApi Properties 4968 //----------------------------------------------------------------------------------------------------------------- 4969 4970 /** 4971 * <i><l>OpenApiCommon</l> configuration property: </i> Default OpenAPI format for HTTP parts. 4972 * 4973 * <p> 4974 * Specifies the format to use for HTTP parts when not otherwise specified via {@link org.apache.juneau.annotation.Schema#format()} for 4975 * the OpenAPI serializer and parser on this client. 4976 * 4977 * <h5 class='section'>Example:</h5> 4978 * <p class='bjava'> 4979 * <jc>// Create a REST client with UON part serialization and parsing.</jc> 4980 * RestClient <jv>client</jv> = RestClient 4981 * .<jsm>create</jsm>() 4982 * .oapiFormat(<jsf>UON</jsf>) 4983 * .build(); 4984 * 4985 * <jc>// Set a header with a value in UON format.</jc> 4986 * <jv>client</jv> 4987 * .get(<js>"/uri"</js>) 4988 * .header(<js>"Foo"</js>, <js>"bar baz"</js>) <jc>// Will be serialized as: 'bar baz'</jc> 4989 * .run(); 4990 * </p> 4991 * 4992 * <ul class='values javatree'> 4993 * <li class='jc'>{@link org.apache.juneau.httppart.HttpPartFormat} 4994 * <ul> 4995 * <li class='jf'>{@link org.apache.juneau.httppart.HttpPartFormat#UON UON} - UON notation (e.g. <js>"'foo bar'"</js>). 4996 * <li class='jf'>{@link org.apache.juneau.httppart.HttpPartFormat#INT32 INT32} - Signed 32 bits. 4997 * <li class='jf'>{@link org.apache.juneau.httppart.HttpPartFormat#INT64 INT64} - Signed 64 bits. 4998 * <li class='jf'>{@link org.apache.juneau.httppart.HttpPartFormat#FLOAT FLOAT} - 32-bit floating point number. 4999 * <li class='jf'>{@link org.apache.juneau.httppart.HttpPartFormat#DOUBLE DOUBLE} - 64-bit floating point number. 5000 * <li class='jf'>{@link org.apache.juneau.httppart.HttpPartFormat#BYTE BYTE} - BASE-64 encoded characters. 5001 * <li class='jf'>{@link org.apache.juneau.httppart.HttpPartFormat#BINARY BINARY} - Hexadecimal encoded octets (e.g. <js>"00FF"</js>). 5002 * <li class='jf'>{@link org.apache.juneau.httppart.HttpPartFormat#BINARY_SPACED BINARY_SPACED} - Spaced-separated hexadecimal encoded octets (e.g. <js>"00 FF"</js>). 5003 * <li class='jf'>{@link org.apache.juneau.httppart.HttpPartFormat#DATE DATE} - An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 full-date</a>. 5004 * <li class='jf'>{@link org.apache.juneau.httppart.HttpPartFormat#DATE_TIME DATE_TIME} - An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 date-time</a>. 5005 * <li class='jf'>{@link org.apache.juneau.httppart.HttpPartFormat#PASSWORD PASSWORD} - Used to hint UIs the input needs to be obscured. 5006 * <li class='jf'>{@link org.apache.juneau.httppart.HttpPartFormat#NO_FORMAT NO_FORMAT} - (default) Not specified. 5007 * </ul> 5008 * </ul> 5009 * 5010 * <h5 class='section'>See Also:</h5><ul> 5011 * <li class='jm'>{@link org.apache.juneau.oapi.OpenApiSerializer.Builder#format(HttpPartFormat)} 5012 * <li class='jm'>{@link org.apache.juneau.oapi.OpenApiParser.Builder#format(HttpPartFormat)} 5013 * </ul> 5014 * 5015 * @param value 5016 * The new value for this property. 5017 * <br>The default value is {@link HttpPartFormat#NO_FORMAT}. 5018 * @return This object. 5019 */ 5020 public Builder oapiFormat(HttpPartFormat value) { 5021 serializers().forEach(OpenApiSerializer.Builder.class, x -> x.format(value)); 5022 parsers().forEach(OpenApiParser.Builder.class, x -> x.format(value)); 5023 partSerializer().builder(OpenApiSerializer.Builder.class).ifPresent(x -> x.format(value)); 5024 partParser().builder(OpenApiParser.Builder.class).ifPresent(x -> x.format(value)); 5025 return this; 5026 } 5027 5028 /** 5029 * <i><l>OpenApiCommon</l> configuration property: </i> Default collection format for HTTP parts. 5030 * 5031 * <p> 5032 * Specifies the collection format to use for HTTP parts when not otherwise specified via {@link org.apache.juneau.annotation.Schema#collectionFormat()} for the 5033 * OpenAPI serializer and parser on this client. 5034 * 5035 * <h5 class='section'>Example:</h5> 5036 * <p class='bjava'> 5037 * <jc>// Create a REST client with CSV format for http parts.</jc> 5038 * RestClient <jv>client</jv> = RestClient 5039 * .<jsm>create</jsm>() 5040 * .collectionFormat(<jsf>CSV</jsf>) 5041 * .build(); 5042 * 5043 * <jc>// An arbitrary data structure.</jc> 5044 * AList <jv>list</jv> = AList.<jsm>of</jsm>( 5045 * <js>"foo"</js>, 5046 * <js>"bar"</js>, 5047 * AMap.<jsm>of</jsm>( 5048 * <js>"baz"</js>, AList.<jsm>of</jsm>(<js>"qux"</js>,<js>"true"</js>,<js>"123"</js>) 5049 * ) 5050 * ); 5051 * 5052 * <jc>// Set a header with a comma-separated list.</jc> 5053 * <jv>client</jv> 5054 * .get(<js>"/uri"</js>) 5055 * .header(<js>"Foo"</js>, <jv>list</jv>) <jc>// Will be serialized as: foo=bar,baz=qux\,true\,123</jc> 5056 * .run(); 5057 * </p> 5058 * 5059 * <ul class='values javatree'> 5060 * <li class='jc'>{@link HttpPartCollectionFormat} 5061 * <ul> 5062 * <li class='jf'>{@link HttpPartCollectionFormat#CSV CSV} - (default) Comma-separated values (e.g. <js>"foo,bar"</js>). 5063 * <li class='jf'>{@link HttpPartCollectionFormat#SSV SSV} - Space-separated values (e.g. <js>"foo bar"</js>). 5064 * <li class='jf'>{@link HttpPartCollectionFormat#TSV TSV} - Tab-separated values (e.g. <js>"foo\tbar"</js>). 5065 * <li class='jf'>{@link HttpPartCollectionFormat#PIPES PIPES} - Pipe-separated values (e.g. <js>"foo|bar"</js>). 5066 * <li class='jf'>{@link HttpPartCollectionFormat#MULTI MULTI} - Corresponds to multiple parameter instances instead of multiple values for a single instance (e.g. <js>"foo=bar&foo=baz"</js>). 5067 * <li class='jf'>{@link HttpPartCollectionFormat#UONC UONC} - UON collection notation (e.g. <js>"@(foo,bar)"</js>). 5068 * </ul> 5069 * </ul> 5070 * 5071 * <h5 class='section'>See Also:</h5><ul> 5072 * <li class='jm'>{@link org.apache.juneau.oapi.OpenApiSerializer.Builder#collectionFormat(HttpPartCollectionFormat)} 5073 * <li class='jm'>{@link org.apache.juneau.oapi.OpenApiParser.Builder#collectionFormat(HttpPartCollectionFormat)} 5074 * </ul> 5075 * 5076 * @param value 5077 * The new value for this property. 5078 * <br>The default value is {@link HttpPartCollectionFormat#NO_COLLECTION_FORMAT}. 5079 * @return This object. 5080 */ 5081 public Builder oapiCollectionFormat(HttpPartCollectionFormat value) { 5082 serializers().forEach(OpenApiSerializer.Builder.class, x -> x.collectionFormat(value)); 5083 parsers().forEach(OpenApiParser.Builder.class, x -> x.collectionFormat(value)); 5084 partSerializer().builder(OpenApiSerializer.Builder.class, x -> x.collectionFormat(value)); 5085 partParser().builder(OpenApiParser.Builder.class, x -> x.collectionFormat(value)); 5086 return this; 5087 } 5088 5089 //----------------------------------------------------------------------------------------------------------------- 5090 // UON Properties 5091 //----------------------------------------------------------------------------------------------------------------- 5092 5093 /** 5094 * <i><l>UonSerializer</l> configuration property: </i> Parameter format. 5095 * 5096 * <p> 5097 * Specifies the format of parameters when using the {@link UrlEncodingSerializer} to serialize Form Posts. 5098 * 5099 * <p> 5100 * Specifies the format to use for GET parameter keys and values. 5101 * 5102 * <h5 class='section'>Example:</h5> 5103 * <p class='bjava'> 5104 * <jc>// Create a REST client with URL-Encoded serializer that serializes values in plain-text format.</jc> 5105 * RestClient <jv>client</jv> = RestClient 5106 * .<jsm>create</jsm>() 5107 * .urlEnc() 5108 * .paramFormat(<jsf>PLAINTEXT</jsf>) 5109 * .build(); 5110 * 5111 * <jc>// An arbitrary data structure.</jc> 5112 * AMap <jv>map</jv> = AMap.<jsm>of</jsm>( 5113 * <js>"foo"</js>, <js>"bar"</js>, 5114 * <js>"baz"</js>, <jk>new</jk> String[]{<js>"qux"</js>, <js>"true"</js>, <js>"123"</js>} 5115 * ); 5116 * 5117 * <jc>// Request body will be serialized as: foo=bar,baz=qux,true,123</jc> 5118 * <jv>client</jv> 5119 * .post(<js>"/uri"</js>, <jv>map</jv>) 5120 * .run(); 5121 * </p> 5122 * 5123 * <ul class='values javatree'> 5124 * <li class='jf'>{@link ParamFormat#UON} (default) - Use UON notation for parameters. 5125 * <li class='jf'>{@link ParamFormat#PLAINTEXT} - Use plain text for parameters. 5126 * </ul> 5127 * 5128 * <h5 class='section'>See Also:</h5><ul> 5129 * <li class='jm'>{@link org.apache.juneau.uon.UonSerializer.Builder#paramFormat(ParamFormat)} 5130 * </ul> 5131 * 5132 * @param value The new value for this property. 5133 * @return This object. 5134 */ 5135 public Builder paramFormat(ParamFormat value) { 5136 serializers().forEach(UonSerializer.Builder.class, x -> x.paramFormat(value)); 5137 return this; 5138 } 5139 5140 /** 5141 * <i><l>UonSerializer</l> configuration property: </i> Parameter format. 5142 * 5143 * <p> 5144 * Specifies the format of parameters when using the {@link UrlEncodingSerializer} to serialize Form Posts. 5145 * 5146 * <p> 5147 * Specifies plaintext as the format to use for GET parameter keys and values. 5148 * 5149 * <h5 class='section'>Example:</h5> 5150 * <p class='bjava'> 5151 * <jc>// Create a REST client with URL-Encoded serializer that serializes values in plain-text format.</jc> 5152 * RestClient <jv>client</jv> = RestClient 5153 * .<jsm>create</jsm>() 5154 * .urlEnc() 5155 * .build(); 5156 * 5157 * <jc>// An arbitrary data structure.</jc> 5158 * AMap <jv>map</jv> = AMap.<jsm>of</jsm>( 5159 * <js>"foo"</js>, <js>"bar"</js>, 5160 * <js>"baz"</js>, <jk>new</jk> String[]{<js>"qux"</js>, <js>"true"</js>, <js>"123"</js>} 5161 * ); 5162 * 5163 * <jc>// Request body will be serialized as: foo=bar,baz=qux,true,123</jc> 5164 * <jv>client</jv> 5165 * .post(<js>"/uri"</js>, <jv>map</jv>) 5166 * .run(); 5167 * </p> 5168 * 5169 * <h5 class='section'>See Also:</h5><ul> 5170 * <li class='jm'>{@link org.apache.juneau.uon.UonSerializer.Builder#paramFormatPlain()} 5171 * </ul> 5172 * 5173 * @return This object. 5174 */ 5175 public Builder paramFormatPlain() { 5176 serializers().forEach(UonSerializer.Builder.class, org.apache.juneau.uon.UonSerializer.Builder::paramFormatPlain); 5177 return this; 5178 } 5179 @Override /* Overridden from Builder */ 5180 public Builder annotations(Annotation...values) { 5181 super.annotations(values); 5182 return this; 5183 } 5184 5185 @Override /* Overridden from Builder */ 5186 public Builder apply(AnnotationWorkList work) { 5187 super.apply(work); 5188 return this; 5189 } 5190 5191 @Override /* Overridden from Builder */ 5192 public Builder applyAnnotations(Object...from) { 5193 super.applyAnnotations(from); 5194 return this; 5195 } 5196 5197 @Override /* Overridden from Builder */ 5198 public Builder applyAnnotations(Class<?>...from) { 5199 super.applyAnnotations(from); 5200 return this; 5201 } 5202 5203 @Override /* Overridden from Builder */ 5204 public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) { 5205 super.cache(value); 5206 return this; 5207 } 5208 5209 @Override /* Overridden from Builder */ 5210 public Builder impl(Context value) { 5211 super.impl(value); 5212 return this; 5213 } 5214 5215 @Override /* Overridden from Builder */ 5216 public Builder type(Class<? extends org.apache.juneau.Context> value) { 5217 super.type(value); 5218 return this; 5219 } 5220 5221 @Override /* Overridden from Builder */ 5222 public Builder beanClassVisibility(Visibility value) { 5223 super.beanClassVisibility(value); 5224 return this; 5225 } 5226 5227 @Override /* Overridden from Builder */ 5228 public Builder beanConstructorVisibility(Visibility value) { 5229 super.beanConstructorVisibility(value); 5230 return this; 5231 } 5232 5233 @Override /* Overridden from Builder */ 5234 public Builder beanContext(BeanContext value) { 5235 super.beanContext(value); 5236 return this; 5237 } 5238 5239 @Override /* Overridden from Builder */ 5240 public Builder beanContext(BeanContext.Builder value) { 5241 super.beanContext(value); 5242 return this; 5243 } 5244 5245 @Override /* Overridden from Builder */ 5246 public Builder beanDictionary(java.lang.Class<?>...values) { 5247 super.beanDictionary(values); 5248 return this; 5249 } 5250 5251 @Override /* Overridden from Builder */ 5252 public Builder beanFieldVisibility(Visibility value) { 5253 super.beanFieldVisibility(value); 5254 return this; 5255 } 5256 5257 @Override /* Overridden from Builder */ 5258 public Builder beanInterceptor(Class<?> on, Class<? extends org.apache.juneau.swap.BeanInterceptor<?>> value) { 5259 super.beanInterceptor(on, value); 5260 return this; 5261 } 5262 5263 @Override /* Overridden from Builder */ 5264 public Builder beanMethodVisibility(Visibility value) { 5265 super.beanMethodVisibility(value); 5266 return this; 5267 } 5268 5269 @Override /* Overridden from Builder */ 5270 public Builder beanProperties(Map<String,Object> values) { 5271 super.beanProperties(values); 5272 return this; 5273 } 5274 5275 @Override /* Overridden from Builder */ 5276 public Builder beanProperties(Class<?> beanClass, String properties) { 5277 super.beanProperties(beanClass, properties); 5278 return this; 5279 } 5280 5281 @Override /* Overridden from Builder */ 5282 public Builder beanProperties(String beanClassName, String properties) { 5283 super.beanProperties(beanClassName, properties); 5284 return this; 5285 } 5286 5287 @Override /* Overridden from Builder */ 5288 public Builder beanPropertiesExcludes(Map<String,Object> values) { 5289 super.beanPropertiesExcludes(values); 5290 return this; 5291 } 5292 5293 @Override /* Overridden from Builder */ 5294 public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) { 5295 super.beanPropertiesExcludes(beanClass, properties); 5296 return this; 5297 } 5298 5299 @Override /* Overridden from Builder */ 5300 public Builder beanPropertiesExcludes(String beanClassName, String properties) { 5301 super.beanPropertiesExcludes(beanClassName, properties); 5302 return this; 5303 } 5304 5305 @Override /* Overridden from Builder */ 5306 public Builder beanPropertiesReadOnly(Map<String,Object> values) { 5307 super.beanPropertiesReadOnly(values); 5308 return this; 5309 } 5310 5311 @Override /* Overridden from Builder */ 5312 public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) { 5313 super.beanPropertiesReadOnly(beanClass, properties); 5314 return this; 5315 } 5316 5317 @Override /* Overridden from Builder */ 5318 public Builder beanPropertiesReadOnly(String beanClassName, String properties) { 5319 super.beanPropertiesReadOnly(beanClassName, properties); 5320 return this; 5321 } 5322 5323 @Override /* Overridden from Builder */ 5324 public Builder beanPropertiesWriteOnly(Map<String,Object> values) { 5325 super.beanPropertiesWriteOnly(values); 5326 return this; 5327 } 5328 5329 @Override /* Overridden from Builder */ 5330 public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) { 5331 super.beanPropertiesWriteOnly(beanClass, properties); 5332 return this; 5333 } 5334 5335 @Override /* Overridden from Builder */ 5336 public Builder beanPropertiesWriteOnly(String beanClassName, String properties) { 5337 super.beanPropertiesWriteOnly(beanClassName, properties); 5338 return this; 5339 } 5340 5341 @Override /* Overridden from Builder */ 5342 public Builder beansRequireDefaultConstructor() { 5343 super.beansRequireDefaultConstructor(); 5344 return this; 5345 } 5346 5347 @Override /* Overridden from Builder */ 5348 public Builder beansRequireSerializable() { 5349 super.beansRequireSerializable(); 5350 return this; 5351 } 5352 5353 @Override /* Overridden from Builder */ 5354 public Builder beansRequireSettersForGetters() { 5355 super.beansRequireSettersForGetters(); 5356 return this; 5357 } 5358 5359 @Override /* Overridden from Builder */ 5360 public Builder dictionaryOn(Class<?> on, java.lang.Class<?>...values) { 5361 super.dictionaryOn(on, values); 5362 return this; 5363 } 5364 5365 @Override /* Overridden from Builder */ 5366 public Builder disableBeansRequireSomeProperties() { 5367 super.disableBeansRequireSomeProperties(); 5368 return this; 5369 } 5370 5371 @Override /* Overridden from Builder */ 5372 public Builder disableIgnoreMissingSetters() { 5373 super.disableIgnoreMissingSetters(); 5374 return this; 5375 } 5376 5377 @Override /* Overridden from Builder */ 5378 public Builder disableIgnoreTransientFields() { 5379 super.disableIgnoreTransientFields(); 5380 return this; 5381 } 5382 5383 @Override /* Overridden from Builder */ 5384 public Builder disableIgnoreUnknownNullBeanProperties() { 5385 super.disableIgnoreUnknownNullBeanProperties(); 5386 return this; 5387 } 5388 5389 @Override /* Overridden from Builder */ 5390 public Builder disableInterfaceProxies() { 5391 super.disableInterfaceProxies(); 5392 return this; 5393 } 5394 5395 @Override /* Overridden from Builder */ 5396 public Builder findFluentSetters() { 5397 super.findFluentSetters(); 5398 return this; 5399 } 5400 5401 @Override /* Overridden from Builder */ 5402 public Builder findFluentSetters(Class<?> on) { 5403 super.findFluentSetters(on); 5404 return this; 5405 } 5406 5407 @Override /* Overridden from Builder */ 5408 public Builder ignoreInvocationExceptionsOnGetters() { 5409 super.ignoreInvocationExceptionsOnGetters(); 5410 return this; 5411 } 5412 5413 @Override /* Overridden from Builder */ 5414 public Builder ignoreInvocationExceptionsOnSetters() { 5415 super.ignoreInvocationExceptionsOnSetters(); 5416 return this; 5417 } 5418 5419 @Override /* Overridden from Builder */ 5420 public Builder ignoreUnknownBeanProperties() { 5421 super.ignoreUnknownBeanProperties(); 5422 return this; 5423 } 5424 5425 @Override /* Overridden from Builder */ 5426 public Builder ignoreUnknownEnumValues() { 5427 super.ignoreUnknownEnumValues(); 5428 return this; 5429 } 5430 5431 @Override /* Overridden from Builder */ 5432 public Builder implClass(Class<?> interfaceClass, Class<?> implClass) { 5433 super.implClass(interfaceClass, implClass); 5434 return this; 5435 } 5436 5437 @Override /* Overridden from Builder */ 5438 public Builder implClasses(Map<Class<?>,Class<?>> values) { 5439 super.implClasses(values); 5440 return this; 5441 } 5442 5443 @Override /* Overridden from Builder */ 5444 public Builder interfaceClass(Class<?> on, Class<?> value) { 5445 super.interfaceClass(on, value); 5446 return this; 5447 } 5448 5449 @Override /* Overridden from Builder */ 5450 public Builder interfaces(java.lang.Class<?>...value) { 5451 super.interfaces(value); 5452 return this; 5453 } 5454 5455 @Override /* Overridden from Builder */ 5456 public Builder locale(Locale value) { 5457 super.locale(value); 5458 return this; 5459 } 5460 5461 @Override /* Overridden from Builder */ 5462 public Builder notBeanClasses(java.lang.Class<?>...values) { 5463 super.notBeanClasses(values); 5464 return this; 5465 } 5466 5467 @Override /* Overridden from Builder */ 5468 public Builder notBeanPackages(String...values) { 5469 super.notBeanPackages(values); 5470 return this; 5471 } 5472 5473 @Override /* Overridden from Builder */ 5474 public Builder propertyNamer(Class<? extends org.apache.juneau.PropertyNamer> value) { 5475 super.propertyNamer(value); 5476 return this; 5477 } 5478 5479 @Override /* Overridden from Builder */ 5480 public Builder propertyNamer(Class<?> on, Class<? extends org.apache.juneau.PropertyNamer> value) { 5481 super.propertyNamer(on, value); 5482 return this; 5483 } 5484 5485 @Override /* Overridden from Builder */ 5486 public Builder sortProperties() { 5487 super.sortProperties(); 5488 return this; 5489 } 5490 5491 @Override /* Overridden from Builder */ 5492 public Builder sortProperties(java.lang.Class<?>...on) { 5493 super.sortProperties(on); 5494 return this; 5495 } 5496 5497 @Override /* Overridden from Builder */ 5498 public Builder stopClass(Class<?> on, Class<?> value) { 5499 super.stopClass(on, value); 5500 return this; 5501 } 5502 5503 @Override /* Overridden from Builder */ 5504 public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) { 5505 super.swap(normalClass, swappedClass, swapFunction); 5506 return this; 5507 } 5508 5509 @Override /* Overridden from Builder */ 5510 public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) { 5511 super.swap(normalClass, swappedClass, swapFunction, unswapFunction); 5512 return this; 5513 } 5514 5515 @Override /* Overridden from Builder */ 5516 public Builder swaps(Object...values) { 5517 super.swaps(values); 5518 return this; 5519 } 5520 5521 @Override /* Overridden from Builder */ 5522 public Builder swaps(Class<?>...values) { 5523 super.swaps(values); 5524 return this; 5525 } 5526 5527 @Override /* Overridden from Builder */ 5528 public Builder timeZone(TimeZone value) { 5529 super.timeZone(value); 5530 return this; 5531 } 5532 5533 @Override /* Overridden from Builder */ 5534 public Builder typeName(Class<?> on, String value) { 5535 super.typeName(on, value); 5536 return this; 5537 } 5538 5539 @Override /* Overridden from Builder */ 5540 public Builder typePropertyName(String value) { 5541 super.typePropertyName(value); 5542 return this; 5543 } 5544 5545 @Override /* Overridden from Builder */ 5546 public Builder typePropertyName(Class<?> on, String value) { 5547 super.typePropertyName(on, value); 5548 return this; 5549 } 5550 5551 @Override /* Overridden from Builder */ 5552 public Builder useEnumNames() { 5553 super.useEnumNames(); 5554 return this; 5555 } 5556 5557 @Override /* Overridden from Builder */ 5558 public Builder useJavaBeanIntrospector() { 5559 super.useJavaBeanIntrospector(); 5560 return this; 5561 } 5562 //------------------------------------------------------------------------------------------------ 5563 // Passthrough methods for HttpClientBuilder. 5564 //------------------------------------------------------------------------------------------------ 5565 5566 /** 5567 * Disables automatic redirect handling. 5568 * 5569 * @return This object. 5570 * @see HttpClientBuilder#disableRedirectHandling() 5571 */ 5572 public Builder disableRedirectHandling() { 5573 httpClientBuilder().disableRedirectHandling(); 5574 return this; 5575 } 5576 5577 /** 5578 * Assigns {@link RedirectStrategy} instance. 5579 * 5580 * <h5 class='section'>Notes:</h5><ul> 5581 * <li class='note'>This value can be overridden by the {@link #disableRedirectHandling()} method. 5582 * </ul> 5583 * 5584 * @param redirectStrategy New property value. 5585 * @return This object. 5586 * @see HttpClientBuilder#setRedirectStrategy(RedirectStrategy) 5587 */ 5588 public Builder redirectStrategy(RedirectStrategy redirectStrategy) { 5589 httpClientBuilder().setRedirectStrategy(redirectStrategy); 5590 return this; 5591 } 5592 5593 /** 5594 * Assigns default {@link CookieSpec} registry which will be used for request execution if not explicitly set in the client execution context. 5595 * 5596 * @param cookieSpecRegistry New property value. 5597 * @return This object. 5598 * @see HttpClientBuilder#setDefaultCookieSpecRegistry(Lookup) 5599 */ 5600 public Builder defaultCookieSpecRegistry(Lookup<CookieSpecProvider> cookieSpecRegistry) { 5601 httpClientBuilder().setDefaultCookieSpecRegistry(cookieSpecRegistry); 5602 return this; 5603 } 5604 5605 /** 5606 * Assigns {@link HttpRequestExecutor} instance. 5607 * 5608 * @param requestExec New property value. 5609 * @return This object. 5610 * @see HttpClientBuilder#setRequestExecutor(HttpRequestExecutor) 5611 */ 5612 public Builder requestExecutor(HttpRequestExecutor requestExec) { 5613 httpClientBuilder().setRequestExecutor(requestExec); 5614 return this; 5615 } 5616 5617 /** 5618 * Assigns {@link javax.net.ssl.HostnameVerifier} instance. 5619 * 5620 * <h5 class='section'>Notes:</h5><ul> 5621 * <li class='note'>This value can be overridden by the {@link #connectionManager(HttpClientConnectionManager)} 5622 * and the {@link #sslSocketFactory(LayeredConnectionSocketFactory)} methods. 5623 * </ul> 5624 * 5625 * @param hostnameVerifier New property value. 5626 * @return This object. 5627 * @see HttpClientBuilder#setSSLHostnameVerifier(HostnameVerifier) 5628 */ 5629 public Builder sslHostnameVerifier(HostnameVerifier hostnameVerifier) { 5630 httpClientBuilder().setSSLHostnameVerifier(hostnameVerifier); 5631 return this; 5632 } 5633 5634 /** 5635 * Assigns file containing public suffix matcher. 5636 * 5637 * <h5 class='section'>Notes:</h5><ul> 5638 * <li class='note'>Instances of this class can be created with {@link PublicSuffixMatcherLoader}. 5639 * </ul> 5640 * 5641 * @param publicSuffixMatcher New property value. 5642 * @return This object. 5643 * @see HttpClientBuilder#setPublicSuffixMatcher(PublicSuffixMatcher) 5644 */ 5645 public Builder publicSuffixMatcher(PublicSuffixMatcher publicSuffixMatcher) { 5646 httpClientBuilder().setPublicSuffixMatcher(publicSuffixMatcher); 5647 return this; 5648 } 5649 5650 /** 5651 * Assigns {@link SSLContext} instance. 5652 * 5653 * <h5 class='section'>Notes:</h5><ul> 5654 * <li class='note'>This value can be overridden by the {@link #connectionManager(HttpClientConnectionManager)} 5655 * and the {@link #sslSocketFactory(LayeredConnectionSocketFactory)} methods. 5656 * </ul> 5657 * 5658 * @param sslContext New property value. 5659 * @return This object. 5660 * @see HttpClientBuilder#setSSLContext(SSLContext) 5661 */ 5662 public Builder sslContext(SSLContext sslContext) { 5663 httpClientBuilder().setSSLContext(sslContext); 5664 return this; 5665 } 5666 5667 /** 5668 * Assigns {@link LayeredConnectionSocketFactory} instance. 5669 * 5670 * <h5 class='section'>Notes:</h5><ul> 5671 * <li class='note'>This value can be overridden by the {@link #connectionManager(HttpClientConnectionManager)} method. 5672 * </ul> 5673 * 5674 * @param sslSocketFactory New property value. 5675 * @return This object. 5676 * @see HttpClientBuilder#setSSLSocketFactory(LayeredConnectionSocketFactory) 5677 */ 5678 public Builder sslSocketFactory(LayeredConnectionSocketFactory sslSocketFactory) { 5679 httpClientBuilder().setSSLSocketFactory(sslSocketFactory); 5680 return this; 5681 } 5682 5683 /** 5684 * Assigns maximum total connection value. 5685 * 5686 * <h5 class='section'>Notes:</h5><ul> 5687 * <li class='note'>This value can be overridden by the {@link #connectionManager(HttpClientConnectionManager)} method. 5688 * </ul> 5689 * 5690 * @param maxConnTotal New property value. 5691 * @return This object. 5692 * @see HttpClientBuilder#setMaxConnTotal(int) 5693 */ 5694 public Builder maxConnTotal(int maxConnTotal) { 5695 httpClientBuilder().setMaxConnTotal(maxConnTotal); 5696 return this; 5697 } 5698 5699 /** 5700 * Assigns maximum connection per route value. 5701 * 5702 * <h5 class='section'>Notes:</h5><ul> 5703 * <li class='note'>This value can be overridden by the {@link #connectionManager(HttpClientConnectionManager)} method. 5704 * </ul> 5705 * 5706 * @param maxConnPerRoute New property value. 5707 * @return This object. 5708 * @see HttpClientBuilder#setMaxConnPerRoute(int) 5709 */ 5710 public Builder maxConnPerRoute(int maxConnPerRoute) { 5711 httpClientBuilder().setMaxConnPerRoute(maxConnPerRoute); 5712 return this; 5713 } 5714 5715 /** 5716 * Assigns default {@link SocketConfig}. 5717 * 5718 * <h5 class='section'>Notes:</h5><ul> 5719 * <li class='note'>This value can be overridden by the {@link #connectionManager(HttpClientConnectionManager)} method. 5720 * </ul> 5721 * 5722 * @param config New property value. 5723 * @return This object. 5724 * @see HttpClientBuilder#setDefaultSocketConfig(SocketConfig) 5725 */ 5726 public Builder defaultSocketConfig(SocketConfig config) { 5727 httpClientBuilder().setDefaultSocketConfig(config); 5728 return this; 5729 } 5730 5731 /** 5732 * Assigns default {@link ConnectionConfig}. 5733 * 5734 * <h5 class='section'>Notes:</h5><ul> 5735 * <li class='note'>This value can be overridden by the {@link #connectionManager(HttpClientConnectionManager)} method. 5736 * </ul> 5737 * 5738 * @param config New property value. 5739 * @return This object. 5740 * @see HttpClientBuilder#setDefaultConnectionConfig(ConnectionConfig) 5741 */ 5742 public Builder defaultConnectionConfig(ConnectionConfig config) { 5743 httpClientBuilder().setDefaultConnectionConfig(config); 5744 return this; 5745 } 5746 5747 /** 5748 * Sets maximum time to live for persistent connections. 5749 * 5750 * <h5 class='section'>Notes:</h5><ul> 5751 * <li class='note'>This value can be overridden by the {@link #connectionManager(HttpClientConnectionManager)} method. 5752 * </ul> 5753 * 5754 * @param connTimeToLive New property value. 5755 * @param connTimeToLiveTimeUnit New property value. 5756 * @return This object. 5757 * @see HttpClientBuilder#setConnectionTimeToLive(long,TimeUnit) 5758 */ 5759 public Builder connectionTimeToLive(long connTimeToLive, TimeUnit connTimeToLiveTimeUnit) { 5760 httpClientBuilder().setConnectionTimeToLive(connTimeToLive, connTimeToLiveTimeUnit); 5761 return this; 5762 } 5763 5764 /** 5765 * Assigns {@link ConnectionReuseStrategy} instance. 5766 * 5767 * @param reuseStrategy New property value. 5768 * @return This object. 5769 * @see HttpClientBuilder#setConnectionReuseStrategy(ConnectionReuseStrategy) 5770 */ 5771 public Builder connectionReuseStrategy(ConnectionReuseStrategy reuseStrategy) { 5772 httpClientBuilder().setConnectionReuseStrategy(reuseStrategy); 5773 return this; 5774 } 5775 5776 /** 5777 * Assigns {@link ConnectionKeepAliveStrategy} instance. 5778 * 5779 * @param keepAliveStrategy New property value. 5780 * @return This object. 5781 * @see HttpClientBuilder#setKeepAliveStrategy(ConnectionKeepAliveStrategy) 5782 */ 5783 public Builder keepAliveStrategy(ConnectionKeepAliveStrategy keepAliveStrategy) { 5784 httpClientBuilder().setKeepAliveStrategy(keepAliveStrategy); 5785 return this; 5786 } 5787 5788 /** 5789 * Assigns {@link AuthenticationStrategy} instance for target host authentication. 5790 * 5791 * @param targetAuthStrategy New property value. 5792 * @return This object. 5793 * @see HttpClientBuilder#setTargetAuthenticationStrategy(AuthenticationStrategy) 5794 */ 5795 public Builder targetAuthenticationStrategy(AuthenticationStrategy targetAuthStrategy) { 5796 httpClientBuilder().setTargetAuthenticationStrategy(targetAuthStrategy); 5797 return this; 5798 } 5799 5800 /** 5801 * Assigns {@link AuthenticationStrategy} instance for proxy authentication. 5802 * 5803 * @param proxyAuthStrategy New property value. 5804 * @return This object. 5805 * @see HttpClientBuilder#setProxyAuthenticationStrategy(AuthenticationStrategy) 5806 */ 5807 public Builder proxyAuthenticationStrategy(AuthenticationStrategy proxyAuthStrategy) { 5808 httpClientBuilder().setProxyAuthenticationStrategy(proxyAuthStrategy); 5809 return this; 5810 } 5811 5812 /** 5813 * Assigns {@link UserTokenHandler} instance. 5814 * 5815 * <h5 class='section'>Notes:</h5><ul> 5816 * <li class='note'>This value can be overridden by the {@link #disableConnectionState()} method. 5817 * </ul> 5818 * 5819 * @param userTokenHandler New property value. 5820 * @return This object. 5821 * @see HttpClientBuilder#setUserTokenHandler(UserTokenHandler) 5822 */ 5823 public Builder userTokenHandler(UserTokenHandler userTokenHandler) { 5824 httpClientBuilder().setUserTokenHandler(userTokenHandler); 5825 return this; 5826 } 5827 5828 /** 5829 * Disables connection state tracking. 5830 * 5831 * @return This object. 5832 * @see HttpClientBuilder#disableConnectionState() 5833 */ 5834 public Builder disableConnectionState() { 5835 httpClientBuilder().disableConnectionState(); 5836 return this; 5837 } 5838 5839 /** 5840 * Assigns {@link SchemePortResolver} instance. 5841 * 5842 * @param schemePortResolver New property value. 5843 * @return This object. 5844 * @see HttpClientBuilder#setSchemePortResolver(SchemePortResolver) 5845 */ 5846 public Builder schemePortResolver(SchemePortResolver schemePortResolver) { 5847 httpClientBuilder().setSchemePortResolver(schemePortResolver); 5848 return this; 5849 } 5850 5851 /** 5852 * Adds this protocol interceptor to the head of the protocol processing list. 5853 * 5854 * <h5 class='section'>Notes:</h5><ul> 5855 * <li class='note'>This value can be overridden by the {@link #httpProcessor(HttpProcessor)} method. 5856 * </ul> 5857 * 5858 * @param itcp New property value. 5859 * @return This object. 5860 * @see HttpClientBuilder#addInterceptorFirst(HttpResponseInterceptor) 5861 */ 5862 public Builder addInterceptorFirst(HttpResponseInterceptor itcp) { 5863 httpClientBuilder().addInterceptorFirst(itcp); 5864 return this; 5865 } 5866 5867 /** 5868 * Adds this protocol interceptor to the tail of the protocol processing list. 5869 * 5870 * <h5 class='section'>Notes:</h5><ul> 5871 * <li class='note'>This value can be overridden by the {@link #httpProcessor(HttpProcessor)} method. 5872 * </ul> 5873 * 5874 * @param itcp New property value. 5875 * @return This object. 5876 * @see HttpClientBuilder#addInterceptorLast(HttpResponseInterceptor) 5877 */ 5878 public Builder addInterceptorLast(HttpResponseInterceptor itcp) { 5879 httpClientBuilder().addInterceptorLast(itcp); 5880 return this; 5881 } 5882 5883 /** 5884 * Adds this protocol interceptor to the head of the protocol processing list. 5885 * 5886 * <h5 class='section'>Notes:</h5><ul> 5887 * <li class='note'>This value can be overridden by the {@link #httpProcessor(HttpProcessor)} method. 5888 * </ul> 5889 * 5890 * @param itcp New property value. 5891 * @return This object. 5892 * @see HttpClientBuilder#addInterceptorFirst(HttpRequestInterceptor) 5893 */ 5894 public Builder addInterceptorFirst(HttpRequestInterceptor itcp) { 5895 httpClientBuilder().addInterceptorFirst(itcp); 5896 return this; 5897 } 5898 5899 /** 5900 * Adds this protocol interceptor to the tail of the protocol processing list. 5901 * 5902 * <h5 class='section'>Notes:</h5><ul> 5903 * <li class='note'>This value can be overridden by the {@link #httpProcessor(HttpProcessor)} method. 5904 * </ul> 5905 * 5906 * @param itcp New property value. 5907 * @return This object. 5908 * @see HttpClientBuilder#addInterceptorLast(HttpRequestInterceptor) 5909 */ 5910 public Builder addInterceptorLast(HttpRequestInterceptor itcp) { 5911 httpClientBuilder().addInterceptorLast(itcp); 5912 return this; 5913 } 5914 5915 /** 5916 * Disables state (cookie) management. 5917 * 5918 * <h5 class='section'>Notes:</h5><ul> 5919 * <li class='note'>This value can be overridden by the {@link #httpProcessor(HttpProcessor)} method. 5920 * </ul> 5921 * 5922 * @return This object. 5923 * @see HttpClientBuilder#disableCookieManagement() 5924 */ 5925 public Builder disableCookieManagement() { 5926 httpClientBuilder().disableCookieManagement(); 5927 return this; 5928 } 5929 5930 /** 5931 * Disables automatic content decompression. 5932 * 5933 * <h5 class='section'>Notes:</h5><ul> 5934 * <li class='note'>This value can be overridden by the {@link #httpProcessor(HttpProcessor)} method. 5935 * </ul> 5936 * 5937 * @return This object. 5938 * @see HttpClientBuilder#disableContentCompression() 5939 */ 5940 public Builder disableContentCompression() { 5941 httpClientBuilder().disableContentCompression(); 5942 return this; 5943 } 5944 5945 /** 5946 * Disables authentication scheme caching. 5947 * 5948 * <h5 class='section'>Notes:</h5><ul> 5949 * <li class='note'>This value can be overridden by the {@link #httpProcessor(HttpProcessor)} method. 5950 * </ul> 5951 * 5952 * @return This object. 5953 * @see HttpClientBuilder#disableAuthCaching() 5954 */ 5955 public Builder disableAuthCaching() { 5956 httpClientBuilder().disableAuthCaching(); 5957 return this; 5958 } 5959 5960 /** 5961 * Assigns {@link HttpProcessor} instance. 5962 * 5963 * @param httpprocessor New property value. 5964 * @return This object. 5965 * @see HttpClientBuilder#setHttpProcessor(HttpProcessor) 5966 */ 5967 public Builder httpProcessor(HttpProcessor httpprocessor) { 5968 httpClientBuilder().setHttpProcessor(httpprocessor); 5969 return this; 5970 } 5971 5972 /** 5973 * Assigns {@link HttpRequestRetryHandler} instance. 5974 * 5975 * <h5 class='section'>Notes:</h5><ul> 5976 * <li class='note'>This value can be overridden by the {@link #disableAutomaticRetries()} method. 5977 * </ul> 5978 * 5979 * @param retryHandler New property value. 5980 * @return This object. 5981 * @see HttpClientBuilder#setRetryHandler(HttpRequestRetryHandler) 5982 */ 5983 public Builder retryHandler(HttpRequestRetryHandler retryHandler) { 5984 httpClientBuilder().setRetryHandler(retryHandler); 5985 return this; 5986 } 5987 5988 /** 5989 * Disables automatic request recovery and re-execution. 5990 * 5991 * @return This object. 5992 * @see HttpClientBuilder#disableAutomaticRetries() 5993 */ 5994 public Builder disableAutomaticRetries() { 5995 httpClientBuilder().disableAutomaticRetries(); 5996 return this; 5997 } 5998 5999 /** 6000 * Assigns default proxy value. 6001 * 6002 * <h5 class='section'>Notes:</h5><ul> 6003 * <li class='note'>This value can be overridden by the {@link #routePlanner(HttpRoutePlanner)} method. 6004 * </ul> 6005 * 6006 * @param proxy New property value. 6007 * @return This object. 6008 * @see HttpClientBuilder#setProxy(HttpHost) 6009 */ 6010 public Builder proxy(HttpHost proxy) { 6011 httpClientBuilder().setProxy(proxy); 6012 return this; 6013 } 6014 6015 /** 6016 * Assigns {@link HttpRoutePlanner} instance. 6017 * 6018 * @param routePlanner New property value. 6019 * @return This object. 6020 * @see HttpClientBuilder#setRoutePlanner(HttpRoutePlanner) 6021 */ 6022 public Builder routePlanner(HttpRoutePlanner routePlanner) { 6023 httpClientBuilder().setRoutePlanner(routePlanner); 6024 return this; 6025 } 6026 6027 /** 6028 * Assigns {@link ConnectionBackoffStrategy} instance. 6029 * 6030 * @param connectionBackoffStrategy New property value. 6031 * @return This object. 6032 * @see HttpClientBuilder#setConnectionBackoffStrategy(ConnectionBackoffStrategy) 6033 */ 6034 public Builder connectionBackoffStrategy(ConnectionBackoffStrategy connectionBackoffStrategy) { 6035 httpClientBuilder().setConnectionBackoffStrategy(connectionBackoffStrategy); 6036 return this; 6037 } 6038 6039 /** 6040 * Assigns {@link BackoffManager} instance. 6041 * 6042 * @param backoffManager New property value. 6043 * @return This object. 6044 * @see HttpClientBuilder#setBackoffManager(BackoffManager) 6045 */ 6046 public Builder backoffManager(BackoffManager backoffManager) { 6047 httpClientBuilder().setBackoffManager(backoffManager); 6048 return this; 6049 } 6050 6051 /** 6052 * Assigns {@link ServiceUnavailableRetryStrategy} instance. 6053 * 6054 * @param serviceUnavailStrategy New property value. 6055 * @return This object. 6056 * @see HttpClientBuilder#setServiceUnavailableRetryStrategy(ServiceUnavailableRetryStrategy) 6057 */ 6058 public Builder serviceUnavailableRetryStrategy(ServiceUnavailableRetryStrategy serviceUnavailStrategy) { 6059 httpClientBuilder().setServiceUnavailableRetryStrategy(serviceUnavailStrategy); 6060 return this; 6061 } 6062 6063 /** 6064 * Assigns default {@link CookieStore} instance which will be used for request execution if not explicitly set in the client execution context. 6065 * 6066 * @param cookieStore New property value. 6067 * @return This object. 6068 * @see HttpClientBuilder#setDefaultCookieStore(CookieStore) 6069 */ 6070 public Builder defaultCookieStore(CookieStore cookieStore) { 6071 httpClientBuilder().setDefaultCookieStore(cookieStore); 6072 return this; 6073 } 6074 6075 /** 6076 * Assigns default {@link CredentialsProvider} instance which will be used for request execution if not explicitly set in the client execution context. 6077 * 6078 * @param credentialsProvider New property value. 6079 * @return This object. 6080 * @see HttpClientBuilder#setDefaultCredentialsProvider(CredentialsProvider) 6081 */ 6082 public Builder defaultCredentialsProvider(CredentialsProvider credentialsProvider) { 6083 httpClientBuilder().setDefaultCredentialsProvider(credentialsProvider); 6084 return this; 6085 } 6086 6087 /** 6088 * Assigns default {@link org.apache.http.auth.AuthScheme} registry which will be used for request execution if not explicitly set in the client execution context. 6089 * 6090 * @param authSchemeRegistry New property value. 6091 * @return This object. 6092 * @see HttpClientBuilder#setDefaultAuthSchemeRegistry(Lookup) 6093 */ 6094 public Builder defaultAuthSchemeRegistry(Lookup<AuthSchemeProvider> authSchemeRegistry) { 6095 httpClientBuilder().setDefaultAuthSchemeRegistry(authSchemeRegistry); 6096 return this; 6097 } 6098 6099 /** 6100 * Assigns a map of {@link org.apache.http.client.entity.InputStreamFactory InputStreamFactories} to be used for automatic content decompression. 6101 * 6102 * @param contentDecoderMap New property value. 6103 * @return This object. 6104 * @see HttpClientBuilder#setContentDecoderRegistry(Map) 6105 */ 6106 public Builder contentDecoderRegistry(Map<String,InputStreamFactory> contentDecoderMap) { 6107 httpClientBuilder().setContentDecoderRegistry(contentDecoderMap); 6108 return this; 6109 } 6110 6111 /** 6112 * Assigns default {@link RequestConfig} instance which will be used for request execution if not explicitly set in the client execution context. 6113 * 6114 * @param config New property value. 6115 * @return This object. 6116 * @see HttpClientBuilder#setDefaultRequestConfig(RequestConfig) 6117 */ 6118 public Builder defaultRequestConfig(RequestConfig config) { 6119 httpClientBuilder().setDefaultRequestConfig(config); 6120 return this; 6121 } 6122 6123 /** 6124 * Use system properties when creating and configuring default implementations. 6125 * 6126 * @return This object. 6127 * @see HttpClientBuilder#useSystemProperties() 6128 */ 6129 public Builder useSystemProperties() { 6130 httpClientBuilder().useSystemProperties(); 6131 return this; 6132 } 6133 6134 /** 6135 * Makes this instance of {@link HttpClient} proactively evict expired connections from the connection pool using a background thread. 6136 * 6137 * <h5 class='section'>Notes:</h5><ul> 6138 * <li class='note'>One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order to stop and release the background thread. 6139 * <li class='note'>This method has no effect if the instance of {@link HttpClient} is configured to use a shared connection manager. 6140 * <li class='note'>This method may not be used when the instance of {@link HttpClient} is created inside an EJB container. 6141 * </ul> 6142 * 6143 * @return This object. 6144 * @see HttpClientBuilder#evictExpiredConnections() 6145 */ 6146 public Builder evictExpiredConnections() { 6147 httpClientBuilder().evictExpiredConnections(); 6148 return this; 6149 } 6150 6151 /** 6152 * Makes this instance of {@link HttpClient} proactively evict idle connections from the connection pool using a background thread. 6153 * 6154 * <h5 class='section'>Notes:</h5><ul> 6155 * <li class='note'>One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order to stop and release the background thread. 6156 * <li class='note'>This method has no effect if the instance of {@link HttpClient} is configured to use a shared connection manager. 6157 * <li class='note'>This method may not be used when the instance of {@link HttpClient} is created inside an EJB container. 6158 * </ul> 6159 * 6160 * @param maxIdleTime New property value. 6161 * @param maxIdleTimeUnit New property value. 6162 * @return This object. 6163 * @see HttpClientBuilder#evictIdleConnections(long,TimeUnit) 6164 */ 6165 public Builder evictIdleConnections(long maxIdleTime, TimeUnit maxIdleTimeUnit) { 6166 httpClientBuilder().evictIdleConnections(maxIdleTime, maxIdleTimeUnit); 6167 return this; 6168 } 6169 } 6170 6171 //------------------------------------------------------------------------------------------------------------------- 6172 // Instance 6173 //------------------------------------------------------------------------------------------------------------------- 6174 6175 final HeaderList headerData; 6176 final PartList queryData, formData, pathData; 6177 final CloseableHttpClient httpClient; 6178 6179 private final HttpClientConnectionManager connectionManager; 6180 private final boolean keepHttpClientOpen, detectLeaks, skipEmptyHeaderData, skipEmptyQueryData, skipEmptyFormData; 6181 private final BeanStore beanStore; 6182 private final UrlEncodingSerializer urlEncodingSerializer; // Used for form posts only. 6183 final HttpPartSerializer partSerializer; 6184 final HttpPartParser partParser; 6185 private final RestCallHandler callHandler; 6186 private final String rootUrl; 6187 private volatile boolean isClosed = false; 6188 private final StackTraceElement[] creationStack; 6189 private final Logger logger; 6190 final DetailLevel logRequests; 6191 final BiPredicate<RestRequest,RestResponse> logRequestsPredicate; 6192 final Level logRequestsLevel; 6193 final boolean ignoreErrors; 6194 private final boolean logToConsole; 6195 private final PrintStream console; 6196 private StackTraceElement[] closedStack; 6197 private static final ConcurrentHashMap<Class<?>,Context> requestContexts = new ConcurrentHashMap<>(); 6198 6199 // These are read directly by RestCall. 6200 final SerializerSet serializers; 6201 final ParserSet parsers; 6202 Predicate<Integer> errorCodes; 6203 6204 final RestCallInterceptor[] interceptors; 6205 6206 private final Map<Class<?>, HttpPartParser> partParsers = new ConcurrentHashMap<>(); 6207 private final Map<Class<?>, HttpPartSerializer> partSerializers = new ConcurrentHashMap<>(); 6208 6209 // This is lazy-created. 6210 private volatile ExecutorService executorService; 6211 private final boolean executorServiceShutdownOnClose; 6212 6213 private static final 6214 BiPredicate<RestRequest,RestResponse> LOG_REQUESTS_PREDICATE_DEFAULT = (req,res) -> true; 6215 6216 /** 6217 * Constructor. 6218 * 6219 * @param builder The builder for this client. 6220 */ 6221 public RestClient(Builder builder) { 6222 super(builder); 6223 6224 beanStore = builder.beanStore 6225 .addBean(RestClient.class, this); 6226 6227 httpClient = builder.getHttpClient(); 6228 headerData = builder.headers().copy(); 6229 queryData = builder.queryData().copy(); 6230 formData = builder.formData().copy(); 6231 pathData = builder.pathData().copy(); 6232 callHandler = builder.callHandler().run(); 6233 skipEmptyHeaderData = builder.skipEmptyHeaderData; 6234 skipEmptyQueryData = builder.skipEmptyQueryData; 6235 skipEmptyFormData = builder.skipEmptyFormData; 6236 rootUrl = builder.rootUrl; 6237 errorCodes = builder.errorCodes; 6238 connectionManager = builder.connectionManager; 6239 console = builder.console != null ? builder.console : System.err; 6240 executorService = builder.executorService; 6241 executorServiceShutdownOnClose = builder.executorServiceShutdownOnClose; 6242 ignoreErrors = builder.ignoreErrors; 6243 keepHttpClientOpen = builder.keepHttpClientOpen; 6244 detectLeaks = builder.detectLeaks; 6245 logger = builder.logger != null ? builder.logger : Logger.getLogger(RestClient.class.getName()); 6246 logToConsole = builder.logToConsole || isDebug(); 6247 logRequests = builder.logRequests != null ? builder.logRequests : isDebug() ? DetailLevel.FULL : DetailLevel.NONE; 6248 logRequestsLevel = builder.logRequestsLevel != null ? builder.logRequestsLevel : isDebug() ? Level.WARNING : Level.OFF; 6249 logRequestsPredicate = builder.logRequestsPredicate != null ? builder.logRequestsPredicate : LOG_REQUESTS_PREDICATE_DEFAULT; 6250 interceptors = builder.interceptors != null ? builder.interceptors.toArray(EMPTY_REST_CALL_INTERCEPTORS) : EMPTY_REST_CALL_INTERCEPTORS; 6251 serializers = builder.serializers().build(); 6252 parsers = builder.parsers().build(); 6253 partSerializer = builder.partSerializer().create(); 6254 partParser = builder.partParser().create(); 6255 urlEncodingSerializer = builder.urlEncodingSerializer().build(); 6256 creationStack = isDebug() ? Thread.currentThread().getStackTrace() : null; 6257 6258 init(); 6259 } 6260 6261 @Override /* Context */ 6262 public Builder copy() { 6263 throw new NoSuchMethodError("Not implemented."); 6264 } 6265 6266 /** 6267 * Perform optional initialization on builder before it is used. 6268 * 6269 * <p> 6270 * Default behavior is a no-op. 6271 * 6272 * @param builder The builder to initialize. 6273 */ 6274 protected void init(RestClient.Builder builder) {} 6275 6276 /** 6277 * Gets called add the end of the constructor call to perform any post-initialization. 6278 */ 6279 protected void init() { 6280 } 6281 6282 /** 6283 * Calls {@link CloseableHttpClient#close()} on the underlying {@link CloseableHttpClient}. 6284 * 6285 * <p> 6286 * It's good practice to call this method after the client is no longer used. 6287 * 6288 * @throws IOException Thrown by underlying stream. 6289 */ 6290 @Override 6291 public void close() throws IOException { 6292 isClosed = true; 6293 if (! keepHttpClientOpen) 6294 httpClient.close(); 6295 if (executorService != null && executorServiceShutdownOnClose) 6296 executorService.shutdown(); 6297 if (creationStack != null) 6298 closedStack = Thread.currentThread().getStackTrace(); 6299 } 6300 6301 /** 6302 * Same as {@link #close()}, but ignores any exceptions. 6303 */ 6304 public void closeQuietly() { 6305 isClosed = true; 6306 try { 6307 if (! keepHttpClientOpen) 6308 httpClient.close(); 6309 if (executorService != null && executorServiceShutdownOnClose) 6310 executorService.shutdown(); 6311 } catch (Throwable t) {} 6312 if (creationStack != null) 6313 closedStack = Thread.currentThread().getStackTrace(); 6314 } 6315 6316 /** 6317 * Entrypoint for executing all requests and returning a response. 6318 * 6319 * <p> 6320 * Subclasses can override this method to provide specialized handling. 6321 * 6322 * <p> 6323 * The behavior of this method can also be modified by specifying a different {@link RestCallHandler}. 6324 * 6325 * <h5 class='section'>See Also:</h5><ul> 6326 * <li class='jm'>{@link Builder#callHandler()} 6327 * </ul> 6328 * 6329 * @param target The target host for the request. 6330 * <br>Implementations may accept <jk>null</jk> if they can still determine a route, for example to a default 6331 * target or by inspecting the request. 6332 * @param request The request to execute. 6333 * @param context The context to use for the execution, or <jk>null</jk> to use the default context. 6334 * @return 6335 * The response to the request. 6336 * <br>This is always a final response, never an intermediate response with an 1xx status code. 6337 * <br>Whether redirects or authentication challenges will be returned or handled automatically depends on the 6338 * implementation and configuration of this client. 6339 * @throws IOException In case of a problem or the connection was aborted. 6340 * @throws ClientProtocolException In case of an http protocol error. 6341 */ 6342 protected HttpResponse run(HttpHost target, HttpRequest request, HttpContext context) throws ClientProtocolException, IOException { 6343 return callHandler.run(target, request, context); 6344 } 6345 6346 /** 6347 * Perform a <c>GET</c> request against the specified URI. 6348 * 6349 * @param uri 6350 * The URI of the remote REST resource. 6351 * <br>Can be any of the following types: 6352 * <ul> 6353 * <li>{@link URIBuilder} 6354 * <li>{@link URI} 6355 * <li>{@link URL} 6356 * <li>{@link String} 6357 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 6358 * </ul> 6359 * @return 6360 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 6361 * as a parsed object. 6362 * @throws RestCallException If any authentication errors occurred. 6363 */ 6364 public RestRequest get(Object uri) throws RestCallException { 6365 return request(op("GET", uri, NO_BODY)); 6366 } 6367 6368 /** 6369 * Perform a <c>GET</c> request against the root URI. 6370 * 6371 * @return 6372 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 6373 * as a parsed object. 6374 * @throws RestCallException If any authentication errors occurred. 6375 */ 6376 public RestRequest get() throws RestCallException { 6377 return request(op("GET", null, NO_BODY)); 6378 } 6379 6380 /** 6381 * Perform a <c>PUT</c> request against the specified URI. 6382 * 6383 * @param uri 6384 * The URI of the remote REST resource. 6385 * <br>Can be any of the following types: 6386 * <ul> 6387 * <li>{@link URIBuilder} 6388 * <li>{@link URI} 6389 * <li>{@link URL} 6390 * <li>{@link String} 6391 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 6392 * </ul> 6393 * @param body 6394 * The object to serialize and transmit to the URI as the body of the request. 6395 * Can be of the following types: 6396 * <ul class='spaced-list'> 6397 * <li> 6398 * {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource. 6399 * <li> 6400 * {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource. 6401 * <li> 6402 * {@link Object} - POJO to be converted to text using the {@link Serializer} registered with the 6403 * {@link RestClient}. 6404 * <li> 6405 * {@link HttpEntity} / {@link HttpResource} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient. 6406 * <li> 6407 * {@link PartList} - Converted to a URL-encoded FORM post. 6408 * <li> 6409 * {@link Supplier} - A supplier of anything on this list. 6410 * </ul> 6411 * @return 6412 * A {@link RestRequest} object that can be further tailored before executing the request 6413 * and getting the response as a parsed object. 6414 * @throws RestCallException If any authentication errors occurred. 6415 */ 6416 public RestRequest put(Object uri, Object body) throws RestCallException { 6417 return request(op("PUT", uri, body)); 6418 } 6419 6420 /** 6421 * Perform a <c>PUT</c> request against the specified URI using a plain text body bypassing the serializer. 6422 * 6423 * @param uri 6424 * The URI of the remote REST resource. 6425 * <br>Can be any of the following types: 6426 * <ul> 6427 * <li>{@link URIBuilder} 6428 * <li>{@link URI} 6429 * <li>{@link URL} 6430 * <li>{@link String} 6431 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 6432 * </ul> 6433 * @param body 6434 * The object to serialize and transmit to the URI as the body of the request bypassing the serializer. 6435 * @param contentType The content type of the request. 6436 * @return 6437 * A {@link RestRequest} object that can be further tailored before executing the request 6438 * and getting the response as a parsed object. 6439 * @throws RestCallException If any authentication errors occurred. 6440 */ 6441 public RestRequest put(Object uri, String body, ContentType contentType) throws RestCallException { 6442 return request(op("PUT", uri, stringBody(body))).header(contentType); 6443 } 6444 6445 /** 6446 * Same as {@link #put(Object, Object)} but don't specify the input yet. 6447 * 6448 * <p> 6449 * You must call either {@link RestRequest#content(Object)} or {@link RestRequest#formData(String, Object)} 6450 * to set the contents on the result object. 6451 * 6452 * @param uri 6453 * The URI of the remote REST resource. 6454 * <br>Can be any of the following types: 6455 * <ul> 6456 * <li>{@link URIBuilder} 6457 * <li>{@link URI} 6458 * <li>{@link URL} 6459 * <li>{@link String} 6460 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 6461 * </ul> 6462 * @return 6463 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 6464 * as a parsed object. 6465 * @throws RestCallException REST call failed. 6466 */ 6467 public RestRequest put(Object uri) throws RestCallException { 6468 return request(op("PUT", uri, NO_BODY)); 6469 } 6470 6471 /** 6472 * Perform a <c>POST</c> request against the specified URI. 6473 * 6474 * <h5 class='section'>Notes:</h5><ul> 6475 * <li class='note'>Use {@link #formPost(Object, Object)} for <c>application/x-www-form-urlencoded</c> form posts. 6476 * </ul> 6477 * 6478 * @param uri 6479 * The URI of the remote REST resource. 6480 * <br>Can be any of the following types: 6481 * <ul> 6482 * <li>{@link URIBuilder} 6483 * <li>{@link URI} 6484 * <li>{@link URL} 6485 * <li>{@link String} 6486 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 6487 * </ul> 6488 * @param body 6489 * The object to serialize and transmit to the URI as the body of the request. 6490 * Can be of the following types: 6491 * <ul class='spaced-list'> 6492 * <li> 6493 * {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource. 6494 * <li> 6495 * {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource. 6496 * <li> 6497 * {@link Object} - POJO to be converted to text using the {@link Serializer} registered with the 6498 * {@link RestClient}. 6499 * <li> 6500 * {@link HttpEntity} / {@link HttpResource} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient. 6501 * <li> 6502 * {@link PartList} - Converted to a URL-encoded FORM post. 6503 * <li> 6504 * {@link Supplier} - A supplier of anything on this list. 6505 * </ul> 6506 * @return 6507 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 6508 * as a parsed object. 6509 * @throws RestCallException If any authentication errors occurred. 6510 */ 6511 public RestRequest post(Object uri, Object body) throws RestCallException { 6512 return request(op("POST", uri, body)); 6513 } 6514 6515 /** 6516 * Perform a <c>POST</c> request against the specified URI as a plain text body bypassing the serializer. 6517 * 6518 * @param uri 6519 * The URI of the remote REST resource. 6520 * <br>Can be any of the following types: 6521 * <ul> 6522 * <li>{@link URIBuilder} 6523 * <li>{@link URI} 6524 * <li>{@link URL} 6525 * <li>{@link String} 6526 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 6527 * </ul> 6528 * @param body 6529 * The object to serialize and transmit to the URI as the body of the request bypassing the serializer. 6530 * @param contentType 6531 * The content type of the request. 6532 * @return 6533 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 6534 * as a parsed object. 6535 * @throws RestCallException If any authentication errors occurred. 6536 */ 6537 public RestRequest post(Object uri, String body, ContentType contentType) throws RestCallException { 6538 return request(op("POST", uri, stringBody(body))).header(contentType); 6539 } 6540 6541 /** 6542 * Same as {@link #post(Object, Object)} but don't specify the input yet. 6543 * 6544 * <p> 6545 * You must call either {@link RestRequest#content(Object)} or {@link RestRequest#formData(String, Object)} to set the 6546 * contents on the result object. 6547 * 6548 * <h5 class='section'>Notes:</h5><ul> 6549 * <li class='note'>Use {@link #formPost(Object, Object)} for <c>application/x-www-form-urlencoded</c> form posts. 6550 * </ul> 6551 * 6552 * @param uri 6553 * The URI of the remote REST resource. 6554 * <br>Can be any of the following types: 6555 * <ul> 6556 * <li>{@link URIBuilder} 6557 * <li>{@link URI} 6558 * <li>{@link URL} 6559 * <li>{@link String} 6560 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 6561 * </ul> 6562 * @return 6563 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 6564 * as a parsed object. 6565 * @throws RestCallException REST call failed. 6566 */ 6567 public RestRequest post(Object uri) throws RestCallException { 6568 return request(op("POST", uri, NO_BODY)); 6569 } 6570 6571 /** 6572 * Perform a <c>DELETE</c> request against the specified URI. 6573 * 6574 * @param uri 6575 * The URI of the remote REST resource. 6576 * <br>Can be any of the following types: 6577 * <ul> 6578 * <li>{@link URIBuilder} 6579 * <li>{@link URI} 6580 * <li>{@link URL} 6581 * <li>{@link String} 6582 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 6583 * </ul> 6584 * @return 6585 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 6586 * as a parsed object. 6587 * @throws RestCallException If any authentication errors occurred. 6588 */ 6589 public RestRequest delete(Object uri) throws RestCallException { 6590 return request(op("DELETE", uri, NO_BODY)); 6591 } 6592 6593 /** 6594 * Perform an <c>OPTIONS</c> request against the specified URI. 6595 * 6596 * @param uri 6597 * The URI of the remote REST resource. 6598 * <br>Can be any of the following types: 6599 * <ul> 6600 * <li>{@link URIBuilder} 6601 * <li>{@link URI} 6602 * <li>{@link URL} 6603 * <li>{@link String} 6604 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 6605 * </ul> 6606 * @return 6607 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 6608 * as a parsed object. 6609 * @throws RestCallException If any authentication errors occurred. 6610 */ 6611 public RestRequest options(Object uri) throws RestCallException { 6612 return request(op("OPTIONS", uri, NO_BODY)); 6613 } 6614 6615 /** 6616 * Perform a <c>HEAD</c> request against the specified URI. 6617 * 6618 * @param uri 6619 * The URI of the remote REST resource. 6620 * <br>Can be any of the following types: 6621 * <ul> 6622 * <li>{@link URIBuilder} 6623 * <li>{@link URI} 6624 * <li>{@link URL} 6625 * <li>{@link String} 6626 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 6627 * </ul> 6628 * @return 6629 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 6630 * as a parsed object. 6631 * @throws RestCallException If any authentication errors occurred. 6632 */ 6633 public RestRequest head(Object uri) throws RestCallException { 6634 return request(op("HEAD", uri, NO_BODY)); 6635 } 6636 6637 /** 6638 * Perform a <c>POST</c> request with a content type of <c>application/x-www-form-urlencoded</c> 6639 * against the specified URI. 6640 * 6641 * @param uri 6642 * The URI of the remote REST resource. 6643 * <br>Can be any of the following types: 6644 * <ul> 6645 * <li>{@link URIBuilder} 6646 * <li>{@link URI} 6647 * <li>{@link URL} 6648 * <li>{@link String} 6649 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 6650 * </ul> 6651 * @param body 6652 * The object to serialize and transmit to the URI as the body of the request. 6653 * <ul class='spaced-list'> 6654 * <li>{@link NameValuePair} - URL-encoded as a single name-value pair. 6655 * <li>{@link NameValuePair} array - URL-encoded as name value pairs. 6656 * <li>{@link PartList} - URL-encoded as name value pairs. 6657 * <li>{@link Reader}/{@link InputStream}- Streamed directly and <l>Content-Type</l> set to <js>"application/x-www-form-urlencoded"</js> 6658 * <li>{@link HttpResource} - Raw contents will be serialized to remote resource. Additional headers and media type will be set on request. 6659 * <li>{@link HttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient. 6660 * <li>{@link Object} - Converted to a {@link SerializedEntity} using {@link UrlEncodingSerializer} to serialize. 6661 * <li>{@link Supplier} - A supplier of anything on this list. 6662 * </ul> 6663 * @return 6664 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 6665 * as a parsed object. 6666 * @throws RestCallException If any authentication errors occurred. 6667 */ 6668 public RestRequest formPost(Object uri, Object body) throws RestCallException { 6669 RestRequest req = request(op("POST", uri, NO_BODY)); 6670 try { 6671 if (body instanceof Supplier) 6672 body = ((Supplier<?>)body).get(); 6673 if (body instanceof NameValuePair) 6674 return req.content(new UrlEncodedFormEntity(alist((NameValuePair)body))); 6675 if (body instanceof NameValuePair[]) 6676 return req.content(new UrlEncodedFormEntity(alist((NameValuePair[])body))); 6677 if (body instanceof PartList) 6678 return req.content(new UrlEncodedFormEntity(((PartList)body))); 6679 if (body instanceof HttpResource) 6680 ((HttpResource)body).getHeaders().forEach(x-> req.header(x)); 6681 if (body instanceof HttpEntity) { 6682 HttpEntity e = (HttpEntity)body; 6683 if (e.getContentType() == null) 6684 req.header(ContentType.APPLICATION_FORM_URLENCODED); 6685 return req.content(e); 6686 } 6687 if (body instanceof Reader || body instanceof InputStream) 6688 return req.header(ContentType.APPLICATION_FORM_URLENCODED).content(body); 6689 return req.content(serializedEntity(body, urlEncodingSerializer, null)); 6690 } catch (IOException e) { 6691 throw new RestCallException(null, e, "Could not read form post body."); 6692 } 6693 } 6694 6695 /** 6696 * Same as {@link #formPost(Object, Object)} but doesn't specify the input yet. 6697 * 6698 * @param uri 6699 * The URI of the remote REST resource. 6700 * <br>Can be any of the following types: 6701 * <ul> 6702 * <li>{@link URIBuilder} 6703 * <li>{@link URI} 6704 * <li>{@link URL} 6705 * <li>{@link String} 6706 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 6707 * </ul> 6708 * @return 6709 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 6710 * as a parsed object. 6711 * @throws RestCallException If any authentication errors occurred. 6712 */ 6713 public RestRequest formPost(Object uri) throws RestCallException { 6714 return request(op("POST", uri, NO_BODY)); 6715 } 6716 6717 /** 6718 * Perform a <c>POST</c> request with a content type of <c>application/x-www-form-urlencoded</c> 6719 * against the specified URI. 6720 * 6721 * @param uri 6722 * The URI of the remote REST resource. 6723 * <br>Can be any of the following types: 6724 * <ul> 6725 * <li>{@link URIBuilder} 6726 * <li>{@link URI} 6727 * <li>{@link URL} 6728 * <li>{@link String} 6729 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 6730 * </ul> 6731 * @param parameters 6732 * The parameters of the form post. 6733 * <br>The parameters represent name/value pairs and must be an even number of arguments. 6734 * <br>Parameters are converted to {@link BasicPart} objects. 6735 * @return 6736 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 6737 * as a parsed object. 6738 * @throws RestCallException If any authentication errors occurred. 6739 */ 6740 public RestRequest formPostPairs(Object uri, String...parameters) throws RestCallException { 6741 return formPost(uri, partList(parameters)); 6742 } 6743 6744 /** 6745 * Perform a <c>PATCH</c> request against the specified URI. 6746 * 6747 * @param uri 6748 * The URI of the remote REST resource. 6749 * <br>Can be any of the following types: 6750 * <ul> 6751 * <li>{@link URIBuilder} 6752 * <li>{@link URI} 6753 * <li>{@link URL} 6754 * <li>{@link String} 6755 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 6756 * </ul> 6757 * @param body 6758 * The object to serialize and transmit to the URI as the body of the request. 6759 * Can be of the following types: 6760 * <ul class='spaced-list'> 6761 * <li> 6762 * {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource. 6763 * <li> 6764 * {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource. 6765 * <li> 6766 * {@link HttpResource} - Raw contents will be serialized to remote resource. Additional headers and media type will be set on request. 6767 * <li> 6768 * {@link HttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient. 6769 * <li> 6770 * {@link Object} - POJO to be converted to text using the {@link Serializer} registered with the 6771 * {@link RestClient}. 6772 * <li> 6773 * {@link PartList} - Converted to a URL-encoded FORM post. 6774 * <li> 6775 * {@link Supplier} - A supplier of anything on this list. 6776 * </ul> 6777 * @return 6778 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 6779 * as a parsed object. 6780 * @throws RestCallException If any authentication errors occurred. 6781 */ 6782 public RestRequest patch(Object uri, Object body) throws RestCallException { 6783 return request(op("PATCH", uri, body)); 6784 } 6785 6786 /** 6787 * Perform a <c>PATCH</c> request against the specified URI as a plain text body bypassing the serializer. 6788 * 6789 * @param uri 6790 * The URI of the remote REST resource. 6791 * <br>Can be any of the following types: 6792 * <ul> 6793 * <li>{@link URIBuilder} 6794 * <li>{@link URI} 6795 * <li>{@link URL} 6796 * <li>{@link String} 6797 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 6798 * </ul> 6799 * @param body 6800 * The object to serialize and transmit to the URI as the body of the request bypassing the serializer. 6801 * @param contentType 6802 * The content type of the request. 6803 * @return 6804 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 6805 * as a parsed object. 6806 * @throws RestCallException If any authentication errors occurred. 6807 */ 6808 public RestRequest patch(Object uri, String body, ContentType contentType) throws RestCallException { 6809 return request(op("PATCH", uri, stringBody(body))).header(contentType); 6810 } 6811 6812 /** 6813 * Same as {@link #patch(Object, Object)} but don't specify the input yet. 6814 * 6815 * <p> 6816 * You must call {@link RestRequest#content(Object)} to set the contents on the result object. 6817 * 6818 * @param uri 6819 * The URI of the remote REST resource. 6820 * <br>Can be any of the following types: 6821 * <ul> 6822 * <li>{@link URIBuilder} 6823 * <li>{@link URI} 6824 * <li>{@link URL} 6825 * <li>{@link String} 6826 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 6827 * </ul> 6828 * @return 6829 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 6830 * as a parsed object. 6831 * @throws RestCallException REST call failed. 6832 */ 6833 public RestRequest patch(Object uri) throws RestCallException { 6834 return request(op("PATCH", uri, NO_BODY)); 6835 } 6836 6837 6838 /** 6839 * Performs a REST call where the entire call is specified in a simple string. 6840 * 6841 * <p> 6842 * This method is useful for performing callbacks when the target of a callback is passed in 6843 * on an initial request, for example to signal when a long-running process has completed. 6844 * 6845 * <p> 6846 * The call string can be any of the following formats: 6847 * <ul class='spaced-list'> 6848 * <li> 6849 * <js>"[method] [uri]"</js> - e.g. <js>"GET http://localhost/callback"</js> 6850 * <li> 6851 * <js>"[method] [uri] [payload]"</js> - e.g. <js>"POST http://localhost/callback some text payload"</js> 6852 * <li> 6853 * <js>"[method] [headers] [uri] [payload]"</js> - e.g. <js>"POST {'Content-Type':'text/json'} http://localhost/callback {'some':'json'}"</js> 6854 * </ul> 6855 * <p> 6856 * The payload will always be sent using a simple {@link StringEntity}. 6857 * 6858 * @param callString The call string. 6859 * @return 6860 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 6861 * as a parsed object. 6862 * @throws RestCallException REST call failed. 6863 */ 6864 public RestRequest callback(String callString) throws RestCallException { 6865 callString = emptyIfNull(callString); 6866 6867 // S01 - Looking for end of method. 6868 // S02 - Found end of method, looking for beginning of URI or headers. 6869 // S03 - Found beginning of headers, looking for end of headers. 6870 // S04 - Found end of headers, looking for beginning of URI. 6871 // S05 - Found beginning of URI, looking for end of URI. 6872 6873 StateMachineState state = S01; 6874 6875 int mark = 0; 6876 String method = null, headers = null, uri = null, content = null; 6877 for (int i = 0; i < callString.length(); i++) { 6878 char c = callString.charAt(i); 6879 if (state == S01) { 6880 if (isWhitespace(c)) { 6881 method = callString.substring(mark, i); 6882 state = S02; 6883 } 6884 } else if (state == S02) { 6885 if (! isWhitespace(c)) { 6886 mark = i; 6887 if (c == '{') 6888 state = S03; 6889 else 6890 state = S05; 6891 } 6892 } else if (state == S03) { 6893 if (c == '}') { 6894 headers = callString.substring(mark, i+1); 6895 state = S04; 6896 } 6897 } else if (state == S04) { 6898 if (! isWhitespace(c)) { 6899 mark = i; 6900 state = S05; 6901 } 6902 } else /* (state == S05) */ { 6903 if (isWhitespace(c)) { 6904 uri = callString.substring(mark, i); 6905 content = callString.substring(i).trim(); 6906 break; 6907 } 6908 } 6909 } 6910 6911 if (state != S05) 6912 throw new RestCallException(null, null, "Invalid format for call string. State={0}", state); 6913 6914 try { 6915 RestRequest req = request(method, uri, isNotEmpty(content)); 6916 if (headers != null) 6917 JsonMap.ofJson(headers).forEach((k,v) -> req.header(stringHeader(k, s(v)))); 6918 if (isNotEmpty(content)) 6919 req.contentString(content); 6920 return req; 6921 } catch (ParseException e) { 6922 throw new RestCallException(null, e, "Invalid format for call string."); 6923 } 6924 } 6925 6926 /** 6927 * Perform a generic REST call. 6928 * 6929 * @param method The HTTP method. 6930 * @param uri 6931 * The URI of the remote REST resource. 6932 * <br>Can be any of the following types: 6933 * <ul> 6934 * <li>{@link URIBuilder} 6935 * <li>{@link URI} 6936 * <li>{@link URL} 6937 * <li>{@link String} 6938 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 6939 * </ul> 6940 * @param body 6941 * The HTTP body content. 6942 * Can be of the following types: 6943 * <ul class='spaced-list'> 6944 * <li> 6945 * {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource. 6946 * <li> 6947 * {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource. 6948 * <li> 6949 * {@link HttpResource} - Raw contents will be serialized to remote resource. Additional headers and media type will be set on request. 6950 * <li> 6951 * {@link HttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient. 6952 * <li> 6953 * {@link Object} - POJO to be converted to text using the {@link Serializer} registered with the 6954 * {@link RestClient}. 6955 * <li> 6956 * {@link PartList} - Converted to a URL-encoded FORM post. 6957 * <li> 6958 * {@link Supplier} - A supplier of anything on this list. 6959 * </ul> 6960 * This parameter is IGNORED if the method type normally does not have content. 6961 * @return 6962 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 6963 * as a parsed object. 6964 * @throws RestCallException If any authentication errors occurred. 6965 */ 6966 public RestRequest request(String method, Object uri, Object body) throws RestCallException { 6967 return request(op(method, uri, body)); 6968 } 6969 6970 /** 6971 * Perform a generic REST call. 6972 * 6973 * @param method The HTTP method. 6974 * @param uri 6975 * The URI of the remote REST resource. 6976 * <br>Can be any of the following types: 6977 * <ul> 6978 * <li>{@link URIBuilder} 6979 * <li>{@link URI} 6980 * <li>{@link URL} 6981 * <li>{@link String} 6982 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 6983 * </ul> 6984 * @return 6985 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 6986 * as a parsed object. 6987 * @throws RestCallException If any authentication errors occurred. 6988 */ 6989 public RestRequest request(String method, Object uri) throws RestCallException { 6990 return request(op(method, uri, NO_BODY)); 6991 } 6992 6993 /** 6994 * Perform a generic REST call. 6995 * 6996 * <p> 6997 * Typically you're going to use {@link #request(String, Object)} or {@link #request(String, Object, Object)}, 6998 * but this method is provided to allow you to perform non-standard HTTP methods (e.g. HTTP FOO). 6999 * 7000 * @param method The method name (e.g. <js>"GET"</js>, <js>"OPTIONS"</js>). 7001 * @param uri 7002 * The URI of the remote REST resource. 7003 * <br>Can be any of the following types: 7004 * <ul> 7005 * <li>{@link URIBuilder} 7006 * <li>{@link URI} 7007 * <li>{@link URL} 7008 * <li>{@link String} 7009 * <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c> 7010 * </ul> 7011 * @param hasBody Boolean flag indicating if the specified request has content associated with it. 7012 * @return 7013 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 7014 * as a parsed object. 7015 * @throws RestCallException If any authentication errors occurred. 7016 */ 7017 public RestRequest request(String method, Object uri, boolean hasBody) throws RestCallException { 7018 return request(op(method, uri, NO_BODY).hasContent(hasBody)); 7019 } 7020 7021 /** 7022 * Perform an arbitrary request against the specified URI. 7023 * 7024 * <p> 7025 * All requests feed through this method so it can be used to intercept request creations and make modifications 7026 * (such as add headers). 7027 * 7028 * @param op The operation that identifies the HTTP method, URL, and optional payload. 7029 * @return 7030 * A {@link RestRequest} object that can be further tailored before executing the request and getting the response 7031 * as a parsed object. 7032 * @throws RestCallException If any authentication errors occurred. 7033 */ 7034 protected RestRequest request(RestOperation op) throws RestCallException { 7035 if (isClosed) { 7036 Exception e2 = null; 7037 if (closedStack != null) { 7038 e2 = new Exception("Creation stack:"); 7039 e2.setStackTrace(closedStack); 7040 throw new RestCallException(null, e2, "RestClient.close() has already been called. This client cannot be reused."); 7041 } 7042 throw new RestCallException(null, null, "RestClient.close() has already been called. This client cannot be reused. Closed location stack trace can be displayed by setting the system property 'org.apache.juneau.rest.client2.RestClient.trackCreation' to true."); 7043 } 7044 7045 RestRequest req = createRequest(toURI(op.getUri(), rootUrl), op.getMethod(), op.hasContent()); 7046 7047 onCallInit(req); 7048 7049 req.content(op.getContent()); 7050 7051 return req; 7052 } 7053 7054 /** 7055 * Creates a {@link RestRequest} object from the specified {@link HttpRequest} object. 7056 * 7057 * <p> 7058 * Subclasses can override this method to provide their own specialized {@link RestRequest} objects. 7059 * 7060 * @param uri The target. 7061 * @param method The HTTP method (uppercase). 7062 * @param hasBody Whether this method has a request entity. 7063 * @return A new {@link RestRequest} object. 7064 * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt. 7065 */ 7066 protected RestRequest createRequest(URI uri, String method, boolean hasBody) throws RestCallException { 7067 return new RestRequest(this, uri, method, hasBody); 7068 } 7069 7070 /** 7071 * Creates a {@link RestResponse} object from the specified {@link HttpResponse} object. 7072 * 7073 * <p> 7074 * Subclasses can override this method to provide their own specialized {@link RestResponse} objects. 7075 * 7076 * @param request The request creating this response. 7077 * @param httpResponse The response object to wrap. 7078 * @param parser The parser to use to parse the response. 7079 * 7080 * @return A new {@link RestResponse} object. 7081 * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt. 7082 */ 7083 protected RestResponse createResponse(RestRequest request, HttpResponse httpResponse, Parser parser) throws RestCallException { 7084 return new RestResponse(this, request, httpResponse, parser); 7085 } 7086 7087 /** 7088 * Create a new proxy interface against a 3rd-party REST interface. 7089 * 7090 * <p> 7091 * The URI to the REST interface is based on the following values: 7092 * <ul> 7093 * <li>The {@link Remote#path() @Remote(path)} annotation on the interface (<c>remote-path</c>). 7094 * <li>The {@link Builder#rootUrl(Object) rootUrl} on the client (<c>root-url</c>). 7095 * <li>The fully-qualified class name of the interface (<c>class-name</c>). 7096 * </ul> 7097 * 7098 * <p> 7099 * The URI calculation is as follows: 7100 * <ul> 7101 * <li><c>remote-path</c> - If remote path is absolute. 7102 * <li><c>root-uri/remote-path</c> - If remote path is relative and root-uri has been specified. 7103 * <li><c>root-uri/class-name</c> - If remote path is not specified. 7104 * </ul> 7105 * 7106 * <p> 7107 * If the information is not available to resolve to an absolute URI, a {@link RemoteMetadataException} is thrown. 7108 * 7109 * <h5 class='section'>Examples:</h5> 7110 * <p class='bjava'> 7111 * <jk>package</jk> org.apache.foo; 7112 * 7113 * <ja>@RemoteResource</ja>(path=<js>"http://hostname/resturi/myinterface1"</js>) 7114 * <jk>public interface</jk> MyInterface1 { ... } 7115 * 7116 * <ja>@RemoteResource</ja>(path=<js>"/myinterface2"</js>) 7117 * <jk>public interface</jk> MyInterface2 { ... } 7118 * 7119 * <jk>public interface</jk> MyInterface3 { ... } 7120 * 7121 * <jc>// Resolves to "http://localhost/resturi/myinterface1"</jc> 7122 * MyInterface1 <jv>interface1</jv> = RestClient 7123 * .<jsm>create</jsm>() 7124 * .build() 7125 * .getRemote(MyInterface1.<jk>class</jk>); 7126 * 7127 * <jc>// Resolves to "http://hostname/resturi/myinterface2"</jc> 7128 * MyInterface2 <jv>interface2</jv> = RestClient 7129 * .<jsm>create</jsm>() 7130 * .rootUrl(<js>"http://hostname/resturi"</js>) 7131 * .build() 7132 * .getRemote(MyInterface2.<jk>class</jk>); 7133 * 7134 * <jc>// Resolves to "http://hostname/resturi/org.apache.foo.MyInterface3"</jc> 7135 * MyInterface3 <jv>interface3</jv> = RestClient 7136 * .<jsm>create</jsm>() 7137 * .rootUrl(<js>"http://hostname/resturi"</js>) 7138 * .build() 7139 * .getRemote(MyInterface3.<jk>class</jk>); 7140 * </p> 7141 * 7142 * <h5 class='section'>Notes:</h5><ul> 7143 * <li class='note'> 7144 * If you plan on using your proxy in a multi-threaded environment, you'll want to use an underlying 7145 * pooling client connection manager. 7146 * </ul> 7147 * 7148 * <h5 class='section'>See Also:</h5><ul> 7149 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestProxyBasics">REST Proxy Basics</a> 7150 * </ul> 7151 * 7152 * @param <T> The interface to create a proxy for. 7153 * @param interfaceClass The interface to create a proxy for. 7154 * @return The new proxy interface. 7155 * @throws RemoteMetadataException If the REST URI cannot be determined based on the information given. 7156 */ 7157 public <T> T getRemote(Class<T> interfaceClass) { 7158 return getRemote(interfaceClass, null); 7159 } 7160 7161 /** 7162 * Same as {@link #getRemote(Class)} except explicitly specifies the URI of the REST interface. 7163 * 7164 * <h5 class='section'>See Also:</h5><ul> 7165 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestProxyBasics">REST Proxy Basics</a> 7166 * </ul> 7167 * 7168 * @param <T> The interface to create a proxy for. 7169 * @param interfaceClass The interface to create a proxy for. 7170 * @param rootUrl The URI of the REST interface. 7171 * @return The new proxy interface. 7172 */ 7173 public <T> T getRemote(Class<T> interfaceClass, Object rootUrl) { 7174 return getRemote(interfaceClass, rootUrl, null, null); 7175 } 7176 7177 /** 7178 * Same as {@link #getRemote(Class, Object)} but allows you to override the serializer and parser used. 7179 * 7180 * <h5 class='section'>See Also:</h5><ul> 7181 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestProxyBasics">REST Proxy Basics</a> 7182 * </ul> 7183 7184 * @param <T> The interface to create a proxy for. 7185 * @param interfaceClass The interface to create a proxy for. 7186 * @param rootUrl The URI of the REST interface. 7187 * @param serializer The serializer used to serialize POJOs to the body of the HTTP request. 7188 * @param parser The parser used to parse POJOs from the body of the HTTP response. 7189 * @return The new proxy interface. 7190 */ 7191 @SuppressWarnings({ "unchecked" }) 7192 public <T> T getRemote(final Class<T> interfaceClass, Object rootUrl, final Serializer serializer, final Parser parser) { 7193 7194 if (rootUrl == null) 7195 rootUrl = this.rootUrl; 7196 7197 final String restUrl2 = StringUtils.trimSlashes(emptyIfNull(rootUrl)); 7198 7199 return (T)Proxy.newProxyInstance( 7200 interfaceClass.getClassLoader(), 7201 new Class[] { interfaceClass }, 7202 new InvocationHandler() { 7203 7204 final RemoteMeta rm = new RemoteMeta(interfaceClass); 7205 7206 @Override /* InvocationHandler */ 7207 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 7208 RemoteOperationMeta rom = rm.getOperationMeta(method); 7209 7210 String uri = rom.getFullPath(); 7211 if (uri.indexOf("://") == -1) 7212 uri = restUrl2 + '/' + uri; 7213 if (uri.indexOf("://") == -1) 7214 throw new RemoteMetadataException(interfaceClass, "Root URI has not been specified. Cannot construct absolute path to remote resource."); 7215 7216 String httpMethod = rom.getHttpMethod(); 7217 RestRequest rc = request(httpMethod, uri, hasContent(httpMethod)); 7218 7219 rc.serializer(serializer); 7220 rc.parser(parser); 7221 7222 rm.getHeaders().forEach(x -> rc.header(x)); 7223 rom.forEachPathArg(a -> rc.pathArg(a.getName(), args[a.getIndex()], a.getSchema(), a.getSerializer().orElse(partSerializer))); 7224 rom.forEachQueryArg(a -> rc.queryArg(a.getName(), args[a.getIndex()], a.getSchema(), a.getSerializer().orElse(partSerializer), a.isSkipIfEmpty())); 7225 rom.forEachFormDataArg(a -> rc.formDataArg(a.getName(), args[a.getIndex()], a.getSchema(), a.getSerializer().orElse(partSerializer), a.isSkipIfEmpty())); 7226 rom.forEachHeaderArg(a -> rc.headerArg(a.getName(), args[a.getIndex()], a.getSchema(), a.getSerializer().orElse(partSerializer), a.isSkipIfEmpty())); 7227 7228 RemoteOperationArg ba = rom.getContentArg(); 7229 if (ba != null) 7230 rc.content(args[ba.getIndex()], ba.getSchema()); 7231 7232 rom.forEachRequestArg(rmba -> { 7233 RequestBeanMeta rbm = rmba.getMeta(); 7234 Object bean = args[rmba.getIndex()]; 7235 if (bean != null) { 7236 for (RequestBeanPropertyMeta p : rbm.getProperties()) { 7237 Object val = Utils.safeSupplier(()->p.getGetter().invoke(bean)); 7238 HttpPartType pt = p.getPartType(); 7239 String pn = p.getPartName(); 7240 HttpPartSchema schema = p.getSchema(); 7241 if (pt == PATH) 7242 rc.pathArg(pn, val, schema, p.getSerializer().orElse(partSerializer)); 7243 else if (val != null) { 7244 if (pt == QUERY) 7245 rc.queryArg(pn, val, schema, p.getSerializer().orElse(partSerializer), schema.isSkipIfEmpty()); 7246 else if (pt == FORMDATA) 7247 rc.formDataArg(pn, val, schema, p.getSerializer().orElse(partSerializer), schema.isSkipIfEmpty()); 7248 else if (pt == HEADER) 7249 rc.headerArg(pn, val, schema, p.getSerializer().orElse(partSerializer), schema.isSkipIfEmpty()); 7250 else /* (pt == HttpPartType.BODY) */ 7251 rc.content(val, schema); 7252 } 7253 } 7254 } 7255 }); 7256 7257 RemoteOperationReturn ror = rom.getReturns(); 7258 if (ror.isFuture()) { 7259 return getExecutorService().submit(() -> { 7260 try { 7261 return executeRemote(interfaceClass, rc, method, rom); 7262 } catch (Exception e) { 7263 throw e; 7264 } catch (Throwable e) { 7265 throw asRuntimeException(e); 7266 } 7267 }); 7268 } else if (ror.isCompletableFuture()) { 7269 CompletableFuture<Object> cf = new CompletableFuture<>(); 7270 getExecutorService().submit(() -> { 7271 try { 7272 cf.complete(executeRemote(interfaceClass, rc, method, rom)); 7273 } catch (Throwable e) { 7274 cf.completeExceptionally(e); 7275 } 7276 return null; 7277 }); 7278 return cf; 7279 } 7280 7281 return executeRemote(interfaceClass, rc, method, rom); 7282 } 7283 }); 7284 } 7285 7286 Object executeRemote(Class<?> interfaceClass, RestRequest rc, Method method, RemoteOperationMeta rom) throws Throwable { 7287 RemoteOperationReturn ror = rom.getReturns(); 7288 7289 try { 7290 Object ret = null; 7291 RestResponse res = null; 7292 rc.rethrow(RuntimeException.class); 7293 rom.forEachException(x -> rc.rethrow(x)); 7294 if (ror.getReturnValue() == RemoteReturn.NONE) { 7295 res = rc.complete(); 7296 } else if (ror.getReturnValue() == RemoteReturn.STATUS) { 7297 res = rc.complete(); 7298 int returnCode = res.getStatusCode(); 7299 Class<?> rt = method.getReturnType(); 7300 if (rt == Integer.class || rt == int.class) 7301 ret = returnCode; 7302 else if (rt == Boolean.class || rt == boolean.class) 7303 ret = returnCode < 400; 7304 else 7305 throw new RestCallException(res, null, "Invalid return type on method annotated with @RemoteOp(returns=RemoteReturn.STATUS). Only integer and booleans types are valid."); 7306 } else if (ror.getReturnValue() == RemoteReturn.BEAN) { 7307 rc.ignoreErrors(); 7308 res = rc.run(); 7309 ret = res.as(ror.getResponseBeanMeta()); 7310 } else { 7311 Class<?> rt = method.getReturnType(); 7312 if (Throwable.class.isAssignableFrom(rt)) 7313 rc.ignoreErrors(); 7314 res = rc.run(); 7315 Object v = res.getContent().as(ror.getReturnType()); 7316 if (v == null && rt.isPrimitive()) 7317 v = ClassInfo.of(rt).getPrimitiveDefault(); 7318 ret = v; 7319 } 7320 return ret; 7321 } catch (RestCallException e) { 7322 Throwable t = e.getCause(); 7323 if (t instanceof RuntimeException) 7324 throw t; 7325 for (Class<?> t2 : method.getExceptionTypes()) 7326 if (t2.isInstance(t)) 7327 throw t; 7328 throw asRuntimeException(e); 7329 } 7330 } 7331 7332 /** 7333 * Create a new proxy interface against an RRPC-style service. 7334 * 7335 * <p> 7336 * Remote interfaces are interfaces exposed on the server side using either the <c>RrpcServlet</c> 7337 * or <c>RRPC</c> REST methods. 7338 * 7339 * <p> 7340 * The URI to the REST interface is based on the following values: 7341 * <ul> 7342 * <li>The {@link Remote#path() @Remote(path)} annotation on the interface (<c>remote-path</c>). 7343 * <li>The {@link Builder#rootUrl(Object) rootUrl} on the client (<c>root-url</c>). 7344 * <li>The fully-qualified class name of the interface (<c>class-name</c>). 7345 * </ul> 7346 * 7347 * <p> 7348 * The URI calculation is as follows: 7349 * <ul> 7350 * <li><c>remote-path</c> - If remote path is absolute. 7351 * <li><c>root-url/remote-path</c> - If remote path is relative and root-url has been specified. 7352 * <li><c>root-url/class-name</c> - If remote path is not specified. 7353 * </ul> 7354 * 7355 * <p> 7356 * If the information is not available to resolve to an absolute URI, a {@link RemoteMetadataException} is thrown. 7357 * 7358 * <h5 class='section'>Notes:</h5><ul> 7359 * <li class='note'> 7360 * If you plan on using your proxy in a multi-threaded environment, you'll want to use an underlying 7361 * pooling client connection manager. 7362 * </ul> 7363 * 7364 * <h5 class='section'>See Also:</h5><ul> 7365 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestRpc">REST/RPC</a> 7366 * </ul> 7367 * 7368 * @param <T> The interface to create a proxy for. 7369 * @param interfaceClass The interface to create a proxy for. 7370 * @return The new proxy interface. 7371 * @throws RemoteMetadataException If the REST URI cannot be determined based on the information given. 7372 */ 7373 public <T> T getRrpcInterface(final Class<T> interfaceClass) { 7374 return getRrpcInterface(interfaceClass, null); 7375 } 7376 7377 /** 7378 * Same as {@link #getRrpcInterface(Class)} except explicitly specifies the URI of the REST interface. 7379 * 7380 * <h5 class='section'>See Also:</h5><ul> 7381 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestRpc">REST/RPC</a> 7382 * </ul> 7383 * 7384 * @param <T> The interface to create a proxy for. 7385 * @param interfaceClass The interface to create a proxy for. 7386 * @param uri The URI of the REST interface. 7387 * @return The new proxy interface. 7388 */ 7389 public <T> T getRrpcInterface(final Class<T> interfaceClass, final Object uri) { 7390 return getRrpcInterface(interfaceClass, uri, null, null); 7391 } 7392 7393 /** 7394 * Same as {@link #getRrpcInterface(Class, Object)} but allows you to override the serializer and parser used. 7395 * 7396 * <h5 class='section'>See Also:</h5><ul> 7397 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestRpc">REST/RPC</a> 7398 * </ul> 7399 * 7400 * @param <T> The interface to create a proxy for. 7401 * @param interfaceClass The interface to create a proxy for. 7402 * @param uri The URI of the REST interface. 7403 * @param serializer The serializer used to serialize POJOs to the body of the HTTP request. 7404 * @param parser The parser used to parse POJOs from the body of the HTTP response. 7405 * @return The new proxy interface. 7406 */ 7407 @SuppressWarnings({ "unchecked" }) 7408 public <T> T getRrpcInterface(final Class<T> interfaceClass, Object uri, final Serializer serializer, final Parser parser) { 7409 7410 if (uri == null) { 7411 RrpcInterfaceMeta rm = new RrpcInterfaceMeta(interfaceClass, ""); 7412 String path = rm.getPath(); 7413 if (path.indexOf("://") == -1) { 7414 if (isEmpty(rootUrl)) 7415 throw new RemoteMetadataException(interfaceClass, "Root URI has not been specified. Cannot construct absolute path to remote interface."); 7416 path = StringUtils.trimSlashes(rootUrl) + '/' + path; 7417 } 7418 uri = path; 7419 } 7420 7421 final String restUrl2 = s(uri); 7422 7423 return (T)Proxy.newProxyInstance( 7424 interfaceClass.getClassLoader(), 7425 new Class[] { interfaceClass }, 7426 new InvocationHandler() { 7427 7428 final RrpcInterfaceMeta rm = new RrpcInterfaceMeta(interfaceClass, restUrl2); 7429 7430 @Override /* InvocationHandler */ 7431 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 7432 RrpcInterfaceMethodMeta rim = rm.getMethodMeta(method); 7433 7434 String uri = rim.getUri(); 7435 RestResponse res = null; 7436 7437 try { 7438 RestRequest rc = request("POST", uri, true) 7439 .serializer(serializer) 7440 .content(args) 7441 .rethrow(RuntimeException.class) 7442 .rethrow(method.getExceptionTypes()); 7443 7444 res = rc.run(); 7445 7446 Object v = res.getContent().as(method.getGenericReturnType()); 7447 if (v == null && method.getReturnType().isPrimitive()) 7448 v = ClassInfo.of(method.getReturnType()).getPrimitiveDefault(); 7449 return v; 7450 7451 } catch (Throwable e) { 7452 if (e instanceof RestCallException) { 7453 Throwable t = e.getCause(); 7454 if (t != null) 7455 e = t; 7456 } 7457 if (e instanceof RuntimeException) 7458 throw e; 7459 for (Class<?> t2 : method.getExceptionTypes()) 7460 if (t2.isInstance(e)) 7461 throw e; 7462 throw asRuntimeException(e); 7463 } 7464 } 7465 }); 7466 } 7467 7468 @Override 7469 protected void finalize() throws Throwable { 7470 if (detectLeaks && ! isClosed && ! keepHttpClientOpen) { 7471 StringBuilder sb = new StringBuilder("WARNING: RestClient garbage collected before it was finalized."); // NOT DEBUG 7472 if (creationStack != null) { 7473 sb.append("\nCreation Stack:"); // NOT DEBUG 7474 for (StackTraceElement e : creationStack) 7475 sb.append("\n\t" + e); // NOT DEBUG 7476 } 7477 log(WARNING, sb.toString()); 7478 } 7479 } 7480 7481 /** 7482 * Logs a message. 7483 * 7484 * @param level The log level. 7485 * @param t Thrown exception. Can be <jk>null</jk>. 7486 * @param msg The message. 7487 * @param args Optional message arguments. 7488 */ 7489 protected void log(Level level, Throwable t, String msg, Object...args) { 7490 logger.log(level, t, msg(msg, args)); 7491 if (logToConsole) { 7492 console.println(msg(msg, args).get()); 7493 if (t != null) 7494 t.printStackTrace(console); 7495 } 7496 } 7497 7498 /** 7499 * Logs a message. 7500 * 7501 * @param level The log level. 7502 * @param msg The message with {@link MessageFormat}-style arguments. 7503 * @param args The arguments. 7504 */ 7505 protected void log(Level level, String msg, Object...args) { 7506 logger.log(level, msg(msg, args)); 7507 if (logToConsole) 7508 console.println(msg(msg, args).get()); 7509 } 7510 7511 private Supplier<String> msg(String msg, Object...args) { 7512 return ()->args.length == 0 ? msg : MessageFormat.format(msg, args); 7513 } 7514 7515 /** 7516 * Returns the part serializer associated with this client. 7517 * 7518 * @return The part serializer associated with this client. 7519 */ 7520 protected HttpPartSerializer getPartSerializer() { 7521 return partSerializer; 7522 } 7523 7524 /** 7525 * Returns the part parser associated with this client. 7526 * 7527 * @return The part parser associated with this client. 7528 */ 7529 protected HttpPartParser getPartParser() { 7530 return partParser; 7531 } 7532 7533 /** 7534 * Returns the part serializer instance of the specified type. 7535 * 7536 * @param c The part serializer class. 7537 * @return The part serializer. 7538 */ 7539 protected HttpPartSerializer getPartSerializer(Class<? extends HttpPartSerializer> c) { 7540 HttpPartSerializer x = partSerializers.get(c); 7541 if (x == null) { 7542 try { 7543 x = beanStore.createBean(c).run(); 7544 } catch (ExecutableException e) { 7545 throw asRuntimeException(e); 7546 } 7547 partSerializers.put(c, x); 7548 } 7549 return x; 7550 } 7551 7552 /** 7553 * Returns the part parser instance of the specified type. 7554 * 7555 * @param c The part parser class. 7556 * @return The part parser. 7557 */ 7558 protected HttpPartParser getPartParser(Class<? extends HttpPartParser> c) { 7559 HttpPartParser x = partParsers.get(c); 7560 if (x == null) { 7561 try { 7562 x = beanStore.createBean(c).run(); 7563 } catch (ExecutableException e) { 7564 throw asRuntimeException(e); 7565 } 7566 partParsers.put(c, x); 7567 } 7568 return x; 7569 } 7570 7571 /** 7572 * Returns <jk>true</jk> if empty request header values should be ignored. 7573 * 7574 * @return <jk>true</jk> if empty request header values should be ignored. 7575 */ 7576 protected boolean isSkipEmptyHeaderData() { 7577 return skipEmptyHeaderData; 7578 } 7579 7580 /** 7581 * Returns <jk>true</jk> if empty request query parameter values should be ignored. 7582 * 7583 * @return <jk>true</jk> if empty request query parameter values should be ignored. 7584 */ 7585 protected boolean isSkipEmptyQueryData() { 7586 return skipEmptyQueryData; 7587 } 7588 7589 /** 7590 * Returns <jk>true</jk> if empty request form-data parameter values should be ignored. 7591 * 7592 * @return <jk>true</jk> if empty request form-data parameter values should be ignored. 7593 */ 7594 protected boolean isSkipEmptyFormData() { 7595 return skipEmptyFormData; 7596 } 7597 7598 //----------------------------------------------------------------------------------------------------------------- 7599 // Part list builders methods 7600 //----------------------------------------------------------------------------------------------------------------- 7601 7602 /** 7603 * Creates a mutable copy of the header data defined on this client. 7604 * 7605 * <p> 7606 * Used during the construction of {@link RestRequest} objects. 7607 * 7608 * <p> 7609 * Subclasses can override this method to provide their own builder. 7610 * 7611 * @return A new builder. 7612 */ 7613 public HeaderList createHeaderData() { 7614 return headerData.copy(); 7615 } 7616 7617 /** 7618 * Creates a mutable copy of the query data defined on this client. 7619 * 7620 * <p> 7621 * Used during the construction of {@link RestRequest} objects. 7622 * 7623 * <p> 7624 * Subclasses can override this method to provide their own builder. 7625 * 7626 * @return A new builder. 7627 */ 7628 public PartList createQueryData() { 7629 return queryData.copy(); 7630 } 7631 7632 /** 7633 * Creates a mutable copy of the form data defined on this client. 7634 * 7635 * <p> 7636 * Used during the construction of {@link RestRequest} objects. 7637 * 7638 * <p> 7639 * Subclasses can override this method to provide their own builder. 7640 * 7641 * @return A new builder. 7642 */ 7643 public PartList createFormData() { 7644 return formData.copy(); 7645 } 7646 7647 /** 7648 * Creates a mutable copy of the path data defined on this client. 7649 * 7650 * <p> 7651 * Used during the construction of {@link RestRequest} objects. 7652 * 7653 * <p> 7654 * Subclasses can override this method to provide their own builder. 7655 * 7656 * @return A new builder. 7657 */ 7658 public PartList createPathData() { 7659 return pathData.copy(); 7660 } 7661 7662 //----------------------------------------------------------------------------------------------------------------- 7663 // RestCallInterceptor methods 7664 //----------------------------------------------------------------------------------------------------------------- 7665 7666 /** 7667 * Interceptor method called immediately after the RestRequest object is created and all headers/query/form-data has been copied from the client. 7668 * 7669 * <p> 7670 * Subclasses can override this method to intercept the request and perform special modifications. 7671 * 7672 * <h5 class='section'>See Also:</h5><ul> 7673 * <li class='jm'>{@link Builder#interceptors(Object...)} 7674 * </ul> 7675 * 7676 * @param req The HTTP request. 7677 * @throws RestCallException If any of the interceptors threw an exception. 7678 */ 7679 protected void onCallInit(RestRequest req) throws RestCallException { 7680 try { 7681 for (RestCallInterceptor rci : interceptors) 7682 rci.onInit(req); 7683 } catch (RuntimeException | RestCallException e) { 7684 throw e; 7685 } catch (Exception e) { 7686 throw new RestCallException(null, e, "Interceptor threw an exception on init."); 7687 } 7688 } 7689 7690 /** 7691 * Interceptor method called immediately after an HTTP response has been received. 7692 * 7693 * <p> 7694 * Subclasses can override this method to intercept the response and perform special modifications. 7695 * 7696 * <h5 class='section'>See Also:</h5><ul> 7697 * <li class='jm'>{@link Builder#interceptors(Object...)} 7698 * </ul> 7699 * 7700 * @param req The HTTP request. 7701 * @param res The HTTP response. 7702 * @throws RestCallException If any of the interceptors threw an exception. 7703 */ 7704 protected void onCallConnect(RestRequest req, RestResponse res) throws RestCallException { 7705 try { 7706 for (RestCallInterceptor rci : interceptors) 7707 rci.onConnect(req, res); 7708 } catch (RuntimeException | RestCallException e) { 7709 throw e; 7710 } catch (Exception e) { 7711 throw new RestCallException(res, e, "Interceptor threw an exception on connect."); 7712 } 7713 } 7714 7715 /** 7716 * Interceptor method called immediately after the RestRequest object is created and all headers/query/form-data has been set on the request from the client. 7717 * 7718 * <p> 7719 * Subclasses can override this method to handle any cleanup operations. 7720 * 7721 * <h5 class='section'>See Also:</h5><ul> 7722 * <li class='jm'>{@link Builder#interceptors(Object...)} 7723 * </ul> 7724 * 7725 * @param req The HTTP request. 7726 * @param res The HTTP response. 7727 * @throws RestCallException If any of the interceptors threw an exception. 7728 */ 7729 protected void onCallClose(RestRequest req, RestResponse res) throws RestCallException { 7730 try { 7731 for (RestCallInterceptor rci : interceptors) 7732 rci.onClose(req, res); 7733 } catch (RuntimeException | RestCallException e) { 7734 throw e; 7735 } catch (Exception e) { 7736 throw new RestCallException(res, e, "Interceptor threw an exception on close."); 7737 } 7738 } 7739 7740 //------------------------------------------------------------------------------------------------ 7741 // Passthrough methods for HttpClient. 7742 //------------------------------------------------------------------------------------------------ 7743 7744 /** 7745 * Obtains the parameters for this client. 7746 * 7747 * These parameters will become defaults for all requests being executed with this client, and for the parameters of dependent objects in this client. 7748 * 7749 * @return The default parameters. 7750 * @deprecated Use {@link RequestConfig}. 7751 */ 7752 @Deprecated 7753 @Override /* HttpClient */ 7754 public HttpParams getParams() { 7755 return httpClient.getParams(); 7756 } 7757 7758 /** 7759 * Obtains the connection manager used by this client. 7760 * 7761 * @return The connection manager. 7762 * @deprecated Use {@link HttpClientBuilder}. 7763 */ 7764 @Deprecated 7765 @Override /* HttpClient */ 7766 public ClientConnectionManager getConnectionManager() { 7767 return httpClient.getConnectionManager(); 7768 } 7769 7770 /** 7771 * Returns the connection manager if one was specified in the client builder. 7772 * 7773 * @return The connection manager. May be <jk>null</jk>. 7774 */ 7775 public HttpClientConnectionManager getHttpClientConnectionManager() { 7776 return connectionManager; 7777 } 7778 7779 /** 7780 * Executes HTTP request using the default context. 7781 * 7782 * <h5 class='section'>Notes:</h5><ul> 7783 * <li class='note'>This method gets passed on directly to the underlying {@link HttpClient} class. 7784 * </ul> 7785 * 7786 * @param request The request to execute. 7787 * @return 7788 * The response to the request. 7789 * <br>This is always a final response, never an intermediate response with an 1xx status code. 7790 * <br>Whether redirects or authentication challenges will be returned or handled automatically depends on the 7791 * implementation and configuration of this client. 7792 * @throws IOException In case of a problem or the connection was aborted. 7793 * @throws ClientProtocolException In case of an http protocol error. 7794 */ 7795 @Override /* HttpClient */ 7796 public HttpResponse execute(HttpUriRequest request) throws IOException, ClientProtocolException { 7797 return httpClient.execute(request); 7798 } 7799 7800 /** 7801 * Executes HTTP request using the given context. 7802 * 7803 * <h5 class='section'>Notes:</h5><ul> 7804 * <li class='note'>This method gets passed on directly to the underlying {@link HttpClient} class. 7805 * </ul> 7806 * 7807 * @param request The request to execute. 7808 * @param context The context to use for the execution, or <jk>null</jk> to use the default context. 7809 * @return 7810 * The response to the request. 7811 * <br>This is always a final response, never an intermediate response with an 1xx status code. 7812 * <br>Whether redirects or authentication challenges will be returned or handled automatically depends on the 7813 * implementation and configuration of this client. 7814 * @throws IOException In case of a problem or the connection was aborted. 7815 * @throws ClientProtocolException In case of an http protocol error. 7816 */ 7817 @Override /* HttpClient */ 7818 public HttpResponse execute(HttpUriRequest request, HttpContext context) throws IOException, ClientProtocolException { 7819 return httpClient.execute(request, context); 7820 } 7821 7822 /** 7823 * Executes HTTP request using the default context. 7824 * 7825 * <h5 class='section'>Notes:</h5><ul> 7826 * <li class='note'>This method gets passed on directly to the underlying {@link HttpClient} class. 7827 * </ul> 7828 * 7829 * @param target The target host for the request. 7830 * <br>Implementations may accept <jk>null</jk> if they can still determine a route, for example to a default 7831 * target or by inspecting the request. 7832 * @param request The request to execute. 7833 * @return The response to the request. 7834 * <br>This is always a final response, never an intermediate response with an 1xx status code. 7835 * <br>Whether redirects or authentication challenges will be returned or handled automatically depends on the 7836 * implementation and configuration of this client. 7837 * @throws IOException In case of a problem or the connection was aborted. 7838 * @throws ClientProtocolException In case of an http protocol error. 7839 */ 7840 @Override /* HttpClient */ 7841 public HttpResponse execute(HttpHost target, HttpRequest request) throws IOException, ClientProtocolException { 7842 return httpClient.execute(target, request); 7843 } 7844 7845 /** 7846 * Executes HTTP request using the given context. 7847 * 7848 * <h5 class='section'>Notes:</h5><ul> 7849 * <li class='note'>This method gets passed on directly to the underlying {@link HttpClient} class. 7850 * <li class='note'>The {@link #run(HttpHost,HttpRequest,HttpContext)} method has been provided as a wrapper around this method. 7851 * Subclasses can override these methods for handling requests with and without bodies separately. 7852 * <li class='note'>The {@link RestCallHandler} interface can also be implemented to intercept this method. 7853 * </ul> 7854 * 7855 * @param target The target host for the request. 7856 * <br>Implementations may accept <jk>null</jk> if they can still determine a route, for example to a default 7857 * target or by inspecting the request. 7858 * @param request The request to execute. 7859 * @param context The context to use for the execution, or <jk>null</jk> to use the default context. 7860 * @return 7861 * The response to the request. 7862 * <br>This is always a final response, never an intermediate response with an 1xx status code. 7863 * <br>Whether redirects or authentication challenges will be returned or handled automatically depends on the 7864 * implementation and configuration of this client. 7865 * @throws IOException In case of a problem or the connection was aborted. 7866 * @throws ClientProtocolException In case of an http protocol error. 7867 */ 7868 @Override /* HttpClient */ 7869 public HttpResponse execute(HttpHost target, HttpRequest request, HttpContext context) throws IOException, ClientProtocolException { 7870 return httpClient.execute(target, request, context); 7871 } 7872 7873 /** 7874 * Executes HTTP request using the default context and processes the response using the given response handler. 7875 * 7876 * <p> 7877 * The content entity associated with the response is fully consumed and the underlying connection is released back 7878 * to the connection manager automatically in all cases relieving individual {@link ResponseHandler ResponseHandlers} 7879 * from having to manage resource deallocation internally. 7880 * 7881 * <h5 class='section'>Notes:</h5><ul> 7882 * <li class='note'>This method gets passed on directly to the underlying {@link HttpClient} class. 7883 * </ul> 7884 * 7885 * @param request The request to execute. 7886 * @param responseHandler The response handler. 7887 * @return Object returned by response handler. 7888 * @throws IOException In case of a problem or the connection was aborted. 7889 * @throws ClientProtocolException In case of an http protocol error. 7890 */ 7891 @Override /* HttpClient */ 7892 public <T> T execute(HttpUriRequest request, ResponseHandler<? extends T> responseHandler) throws IOException, ClientProtocolException { 7893 return httpClient.execute(request, responseHandler); 7894 } 7895 7896 /** 7897 * Executes HTTP request using the given context and processes the response using the given response handler. 7898 * 7899 * <p> 7900 * The content entity associated with the response is fully consumed and the underlying connection is released back 7901 * to the connection manager automatically in all cases relieving individual {@link ResponseHandler ResponseHandlers} 7902 * from having to manage resource deallocation internally. 7903 * 7904 * <h5 class='section'>Notes:</h5><ul> 7905 * <li class='note'>This method gets passed on directly to the underlying {@link HttpClient} class. 7906 * </ul> 7907 * 7908 * @param request The request to execute. 7909 * @param responseHandler The response handler. 7910 * @param context The context to use for the execution, or <jk>null</jk> to use the default context. 7911 * @return The response object as generated by the response handler. 7912 * @throws IOException In case of a problem or the connection was aborted. 7913 * @throws ClientProtocolException In case of an http protocol error. 7914 */ 7915 @Override /* HttpClient */ 7916 public <T> T execute(HttpUriRequest request, ResponseHandler<? extends T> responseHandler, HttpContext context) throws IOException, ClientProtocolException { 7917 return httpClient.execute(request, responseHandler, context); 7918 } 7919 7920 /** 7921 * Executes HTTP request to the target using the default context and processes the response using the given response handler. 7922 * 7923 * <p> 7924 * The content entity associated with the response is fully consumed and the underlying connection is released back 7925 * to the connection manager automatically in all cases relieving individual {@link ResponseHandler ResponseHandlers} 7926 * from having to manage resource deallocation internally. 7927 * 7928 * <h5 class='section'>Notes:</h5><ul> 7929 * <li class='note'>This method gets passed on directly to the underlying {@link HttpClient} class. 7930 * </ul> 7931 * 7932 * @param target 7933 * The target host for the request. 7934 * <br>Implementations may accept <jk>null</jk> if they can still determine a route, for example to a default target or by inspecting the request. 7935 * @param request The request to execute. 7936 * @param responseHandler The response handler. 7937 * @return The response object as generated by the response handler. 7938 * @throws IOException In case of a problem or the connection was aborted. 7939 * @throws ClientProtocolException In case of an http protocol error. 7940 */ 7941 @Override /* HttpClient */ 7942 public <T> T execute(HttpHost target, HttpRequest request, ResponseHandler<? extends T> responseHandler) throws IOException, ClientProtocolException { 7943 return httpClient.execute(target, request, responseHandler); 7944 } 7945 7946 /** 7947 * Executes a request using the default context and processes the response using the given response handler. 7948 * 7949 * <p> 7950 * The content entity associated with the response is fully consumed and the underlying connection is released back 7951 * to the connection manager automatically in all cases relieving individual {@link ResponseHandler ResponseHandlers} 7952 * from having to manage resource deallocation internally. 7953 * 7954 * <h5 class='section'>Notes:</h5><ul> 7955 * <li class='note'>This method gets passed on directly to the underlying {@link HttpClient} class. 7956 * </ul> 7957 * 7958 * @param target 7959 * The target host for the request. 7960 * <br>Implementations may accept <jk>null</jk> if they can still determine a route, for example to a default target or by inspecting the request. 7961 * @param request The request to execute. 7962 * @param responseHandler The response handler. 7963 * @param context The context to use for the execution, or <jk>null</jk> to use the default context. 7964 * @return The response object as generated by the response handler. 7965 * @throws IOException In case of a problem or the connection was aborted. 7966 * @throws ClientProtocolException In case of an http protocol error. 7967 */ 7968 @Override /* HttpClient */ 7969 public <T> T execute(HttpHost target, HttpRequest request, ResponseHandler<? extends T> responseHandler, HttpContext context) throws IOException, ClientProtocolException { 7970 return httpClient.execute(target, request, responseHandler, context); 7971 } 7972 7973 //----------------------------------------------------------------------------------------------------------------- 7974 // Other methods 7975 //----------------------------------------------------------------------------------------------------------------- 7976 7977 private Pattern absUrlPattern = Pattern.compile("^\\w+\\:\\/\\/.*"); 7978 7979 URI toURI(Object x, String rootUrl) throws RestCallException { 7980 try { 7981 if (x instanceof URI) 7982 return (URI)x; 7983 if (x instanceof URL) 7984 ((URL)x).toURI(); 7985 if (x instanceof URIBuilder) 7986 return ((URIBuilder)x).build(); 7987 String s = x == null ? "" : x.toString(); 7988 if (rootUrl != null && ! absUrlPattern.matcher(s).matches()) { 7989 if (s.isEmpty()) 7990 s = rootUrl; 7991 else { 7992 StringBuilder sb = new StringBuilder(rootUrl); 7993 if (! s.startsWith("/")) 7994 sb.append('/'); 7995 sb.append(s); 7996 s = sb.toString(); 7997 } 7998 } 7999 s = StringUtils.fixUrl(s); 8000 return new URI(s); 8001 } catch (URISyntaxException e) { 8002 throw new RestCallException(null, e, "Invalid URI encountered: {0}", x); // Shouldn't happen. 8003 } 8004 } 8005 8006 ExecutorService getExecutorService() { 8007 if (executorService != null) 8008 return executorService; 8009 synchronized(this) { 8010 executorService = new ThreadPoolExecutor(1, 1, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10)); 8011 return executorService; 8012 } 8013 } 8014 8015 /* 8016 * Returns the serializer that best matches the specified content type. 8017 * If no match found or the content type is null, returns the serializer in the list if it's a list of one. 8018 * Returns null if no serializers are defined. 8019 */ 8020 Serializer getMatchingSerializer(String mediaType) { 8021 if (serializers.isEmpty()) 8022 return null; 8023 if (mediaType != null) { 8024 Serializer s = serializers.getSerializer(mediaType); 8025 if (s != null) 8026 return s; 8027 } 8028 List<Serializer> l = serializers.getSerializers(); 8029 return (l.size() == 1 ? l.get(0) : null); 8030 } 8031 8032 boolean hasSerializers() { 8033 return ! serializers.getSerializers().isEmpty(); 8034 } 8035 8036 /* 8037 * Returns the parser that best matches the specified content type. 8038 * If no match found or the content type is null, returns the parser in the list if it's a list of one. 8039 * Returns null if no parsers are defined. 8040 */ 8041 Parser getMatchingParser(String mediaType) { 8042 if (parsers.isEmpty()) 8043 return null; 8044 if (mediaType != null) { 8045 Parser p = parsers.getParser(mediaType); 8046 if (p != null) 8047 return p; 8048 } 8049 List<Parser> l = parsers.getParsers(); 8050 return (l.size() == 1 ? l.get(0) : null); 8051 } 8052 8053 boolean hasParsers() { 8054 return ! parsers.getParsers().isEmpty(); 8055 } 8056 8057 @SuppressWarnings("unchecked") 8058 <T extends Context> T getInstance(Class<T> c) { 8059 Context o = requestContexts.get(c); 8060 if (o == null) { 8061 if (Serializer.class.isAssignableFrom(c)) { 8062 o = Serializer.createSerializerBuilder((Class<? extends Serializer>)c).beanContext(getBeanContext()).build(); 8063 } else if (Parser.class.isAssignableFrom(c)) { 8064 o = Parser.createParserBuilder((Class<? extends Parser>)c).beanContext(getBeanContext()).build(); 8065 } 8066 requestContexts.put(c, o); 8067 } 8068 return (T)o; 8069 } 8070 8071 private RestOperation op(String method, Object url, Object body) { 8072 return RestOperation.of(method, url, body); 8073 } 8074 8075 private Reader stringBody(String body) { 8076 return body == null ? null : new StringReader(s(body)); 8077 } 8078 8079 @Override /* Context */ 8080 protected JsonMap properties() { 8081 return filteredMap() 8082 .append("errorCodes", errorCodes) 8083 .append("executorService", executorService) 8084 .append("executorServiceShutdownOnClose", executorServiceShutdownOnClose) 8085 .append("headerData", headerData) 8086 .append("interceptors", interceptors) 8087 .append("keepHttpClientOpen", keepHttpClientOpen) 8088 .append("partParser", partParser) 8089 .append("partSerializer", partSerializer) 8090 .append("queryData", queryData) 8091 .append("rootUrl", rootUrl); 8092 } 8093}