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