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