001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.rest.client;
018
019import static java.util.stream.Collectors.toList;
020import static org.apache.juneau.commons.utils.AssertionUtils.*;
021import static org.apache.juneau.commons.utils.CollectionUtils.*;
022import static org.apache.juneau.commons.utils.IoUtils.*;
023import static org.apache.juneau.commons.utils.ThrowableUtils.*;
024import static org.apache.juneau.commons.utils.Utils.*;
025import static org.apache.juneau.http.HttpEntities.*;
026import static org.apache.juneau.http.HttpHeaders.*;
027import static org.apache.juneau.httppart.HttpPartType.*;
028import static org.apache.juneau.rest.client.RestOperation.*;
029
030import java.io.*;
031import java.lang.reflect.*;
032import java.net.*;
033import java.text.*;
034import java.util.*;
035import java.util.concurrent.*;
036import java.util.function.*;
037import java.util.logging.*;
038
039import org.apache.http.*;
040import org.apache.http.ParseException;
041import org.apache.http.client.config.*;
042import org.apache.http.client.entity.*;
043import org.apache.http.client.methods.*;
044import org.apache.http.client.utils.*;
045import org.apache.http.concurrent.*;
046import org.apache.http.entity.BasicHttpEntity;
047import org.apache.http.params.*;
048import org.apache.http.protocol.*;
049import org.apache.juneau.*;
050import org.apache.juneau.commons.collections.FluentMap;
051import org.apache.juneau.commons.reflect.*;
052import org.apache.juneau.html.*;
053import org.apache.juneau.http.*;
054import org.apache.juneau.http.HttpHeaders;
055import org.apache.juneau.http.entity.*;
056import org.apache.juneau.http.header.*;
057import org.apache.juneau.http.header.ContentType;
058import org.apache.juneau.http.part.*;
059import org.apache.juneau.http.resource.*;
060import org.apache.juneau.httppart.*;
061import org.apache.juneau.json.*;
062import org.apache.juneau.msgpack.*;
063import org.apache.juneau.oapi.*;
064import org.apache.juneau.parser.*;
065import org.apache.juneau.plaintext.*;
066import org.apache.juneau.serializer.*;
067import org.apache.juneau.uon.*;
068import org.apache.juneau.urlencoding.*;
069import org.apache.juneau.xml.*;
070
071/**
072 * Represents a request to a remote REST resource.
073 *
074 * <p>
075 * Instances of this class are created by the various creator methods on the {@link RestClient} class.
076 *
077 * <h5 class='section'>Example:</h5>
078 * <p class='bjava'>
079 *    <jc>// Create a request and automatically close it.</jc>
080 *    <jk>try</jk> (<jv>RestRequest</jv> <jv>req</jv> = <jv>client</jv>.get(<js>"/myResource"</js>)) {
081 *       <jv>req</jv>
082 *          .queryData(<js>"foo"</js>, <js>"bar"</js>)
083 *          .run()
084 *          .assertStatus().asCode().is(200);
085 *    }
086 * </p>
087 *
088 * <p>
089 * The {@link #close()} method will automatically close any associated {@link RestResponse} if one was created via {@link #run()}.
090 *
091 * <h5 class='section'>Notes:</h5><ul>
092 *    <li class='warn'>This class is not thread safe.
093 *    <li class='note'>This class implements {@link AutoCloseable} and can be used in try-with-resources blocks.
094 *       The {@link #close()} method allows unchecked exceptions to propagate for debuggability,
095 *       while catching and logging checked exceptions to follow AutoCloseable best practices.
096 * </ul>
097 *
098 * <h5 class='section'>See Also:</h5><ul>
099 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestClientBasics">juneau-rest-client Basics</a>
100 * </ul>
101 */
102@SuppressWarnings("resource")
103public class RestRequest extends BeanSession implements HttpUriRequest, Configurable, AutoCloseable {
104
105   private class SimpleFormData extends SimplePart {
106      SimpleFormData(NameValuePair x) {
107         super(x, client.isSkipEmptyFormData());
108      }
109   }
110
111   private class SimpleHeader extends SimplePart implements Header {
112
113      SimpleHeader(NameValuePair x) {
114         super(x, client.isSkipEmptyHeaderData());
115      }
116
117      @Override
118      public HeaderElement[] getElements() throws ParseException { return null; }
119   }
120
121   private class SimplePart implements NameValuePair {
122      final String name;
123      final String value;
124
125      SimplePart(NameValuePair x, boolean skipIfEmpty) {
126         name = x.getName();
127         if (x instanceof SerializedHeader x2) {
128            value = x2.copyWith(getPartSerializerSession(), null).getValue();
129         } else if (x instanceof SerializedPart x3) {
130            value = x3.copyWith(getPartSerializerSession(), null).getValue();
131         } else {
132            var v = x.getValue();
133            value = (e(v) && skipIfEmpty) ? null : v;
134         }
135      }
136
137      @Override
138      public String getName() { return name; }
139
140      @Override
141      public String getValue() { return value; }
142
143      boolean isValid() {
144         if (e(name) || value == null)
145            return false;
146         return true;
147      }
148   }
149
150   private class SimplePath extends SimplePart {
151      SimplePath(NameValuePair x) {
152         super(x, false);
153      }
154   }
155
156   private class SimpleQuery extends SimplePart {
157      SimpleQuery(NameValuePair x) {
158         super(x, client.isSkipEmptyQueryData());
159      }
160   }
161
162   private static final ContentType TEXT_PLAIN = ContentType.TEXT_PLAIN;
163
164   private static boolean isHeaderArray(Object o) {
165      if (! isArray(o))
166         return false;
167      if (Header.class.isAssignableFrom(o.getClass().getComponentType()))
168         return true;
169      return false;
170   }
171
172   private static boolean isNameValuePairArray(Object o) {
173      if (! isArray(o))
174         return false;
175      if (NameValuePair.class.isAssignableFrom(o.getClass().getComponentType()))
176         return true;
177      return false;
178   }
179
180   @SuppressWarnings("unchecked")
181   private static Map<Object,Object> toMap(Object o) {
182      return (Map<Object,Object>)o;
183   }
184
185   final RestClient client;                               // The client that created this call.
186   private final HttpRequestBase request;                 // The request.
187   private boolean ignoreErrors, suppressLogging;
188   private HttpContext context;
189   private HttpHost target;
190   private HttpPartSchema contentSchema;
191   private HttpPartSerializerSession partSerializerSession;
192   private HeaderList headerData;
193   private List<Class<? extends Throwable>> rethrow;
194   List<RestCallInterceptor> interceptors = list();   // Used for intercepting and altering requests.
195   private Object content;
196   private Parser parser;
197   private PartList formData, pathData, queryData;
198   private Predicate<Integer> errorCodes;
199   private RestResponse response;                         // The response.
200   private Serializer serializer;
201   private URIBuilder uriBuilder;
202
203   private final Map<HttpPartSerializer,HttpPartSerializerSession> partSerializerSessions = new IdentityHashMap<>();
204
205   /**
206    * Constructs a REST call with the specified method name.
207    *
208    * @param client The client that created this request.
209    *    <br>Cannot be <jk>null</jk>.
210    * @param uri The target URI.
211    *    <br>Cannot be <jk>null</jk>.
212    * @param method The HTTP method name (uppercase).
213    *    <br>Cannot be <jk>null</jk>.
214    * @param hasBody Whether this method has a body.
215    * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt.
216    */
217   protected RestRequest(RestClient client, URI uri, String method, boolean hasBody) throws RestCallException {
218      super(assertArgNotNull("client", client).getBeanContext().createSession());
219      this.client = client;
220      this.request = createInnerRequest(assertArgNotNull("method", method), assertArgNotNull("uri", uri), hasBody);
221      this.errorCodes = client.errorCodes;
222      this.formData = client.createFormData();
223      this.headerData = client.createHeaderData();
224      this.ignoreErrors = client.ignoreErrors;
225      this.pathData = client.createPathData();
226      this.queryData = client.createQueryData();
227      this.uriBuilder = new URIBuilder(request.getURI());
228   }
229
230   /**
231    * Aborts this http request. Any active execution of this method should return immediately.
232    *
233    * If the request has not started, it will abort after the next execution.
234    * <br>Aborting this request will cause all subsequent executions with this request to fail.
235    */
236   @Override /* Overridden from HttpUriRequest */
237   public void abort() throws UnsupportedOperationException {
238      request.abort();
239   }
240
241   /**
242    * Sets the value for the <c>Accept</c> request header.
243    *
244    * <p>
245    * This overrides the media type specified on the parser, but is overridden by calling
246    * <code>header(<js>"Accept"</js>, value);</code>
247    *
248    * @param value The new header value.
249    *    <br>Can be <jk>null</jk> (header will not be set).
250    * @return This object.
251    * @throws RestCallException Invalid input.
252    */
253   public RestRequest accept(String value) throws RestCallException {
254      return header(Accept.of(value));
255   }
256
257   /**
258    * Sets the value for the <c>Accept-Charset</c> request header.
259    *
260    * <p>
261    * This is a shortcut for calling <code>header(<js>"Accept-Charset"</js>, value);</code>
262    *
263    * @param value The new header value.
264    *    <br>Can be <jk>null</jk> (header will not be set).
265    * @return This object.
266    * @throws RestCallException Invalid input.
267    */
268   public RestRequest acceptCharset(String value) throws RestCallException {
269      return header(AcceptCharset.of(value));
270   }
271
272   /**
273    * Adds a header to this message.
274    *
275    * The header will be appended to the end of the list.
276    *
277    * <h5 class='section'>Notes:</h5><ul>
278    *    <li class='note'>{@link #header(Header)} is an equivalent method and the preferred method for fluent-style coding.
279    * </ul>
280    *
281    * @param header The header to append.
282    *    <br>Can be <jk>null</jk> (ignored).
283    */
284   @Override /* Overridden from HttpMessage */
285   public void addHeader(Header header) {
286      headerData.append(header);
287   }
288
289   /**
290    * Adds a header to this message.
291    *
292    * The header will be appended to the end of the list.
293    *
294    * <h5 class='section'>Notes:</h5><ul>
295    *    <li class='note'>{@link #header(String,Object)} is an equivalent method and the preferred method for fluent-style coding.
296    * </ul>
297    *
298    * @param name The name of the header.
299    *    <br>Cannot be <jk>null</jk> or empty (header will not be created).
300    * @param value The value of the header.
301    *    <br>Can be <jk>null</jk>.
302    */
303   @Override /* Overridden from HttpMessage */
304   public void addHeader(String name, String value) {
305      headerData.append(stringHeader(name, value));
306   }
307
308   /**
309    * Sets {@link Cancellable} for the ongoing operation.
310    *
311    * @param cancellable The cancellable object.
312    *    <br>Can be <jk>null</jk> (no cancellation will be available).
313    * @return This object.
314    */
315   public RestRequest cancellable(Cancellable cancellable) {
316      request.setCancellable(cancellable);
317      return this;
318   }
319
320   /**
321    * Closes this request and its associated response (if one was created).
322    *
323    * <p>
324    * This method is idempotent and can be called multiple times without side effects.
325    *
326    * <h5 class='section'>Implementation Notes:</h5>
327    * <p>
328    * This implementation represents a compromise between strict AutoCloseable compliance and debuggability:
329    * <ul>
330    *    <li>Unchecked exceptions ({@link RuntimeException} and {@link Error}) from the response close are allowed to propagate.
331    *       This ensures programming errors and serious issues are visible during development and testing.
332    *    <li>Checked exceptions (including {@link RestCallException}) are caught and logged but not thrown.
333    *       This follows AutoCloseable best practices and prevents close exceptions from interfering with
334    *       try-with-resources cleanup or masking the original exception.
335    * </ul>
336    */
337   @Override /* Overridden from AutoCloseable */
338   public void close() {
339      try {
340         if (nn(response)) {
341            response.close();
342         }
343      } catch (RuntimeException | Error e) {
344         // Let unchecked exceptions propagate for debuggability
345         throw e;
346      } catch (Exception e) {
347         // Log checked exceptions but don't throw - follows AutoCloseable best practices
348         client.log(Level.WARNING, e, "Error closing RestResponse");
349      }
350   }
351
352   /**
353    * Same as {@link #run()} but immediately calls {@link RestResponse#consume()} to clean up the response.
354    *
355    * <p>
356    * Use this method if you're only interested in the status line of the response and not the response entity.
357    * Attempts to call any of the methods on the response object that retrieve the body (e.g. {@link ResponseContent#asReader()}
358    * will cause a {@link RestCallException} to be thrown.
359    *
360    * <h5 class='section'>Notes:</h5><ul>
361    *    <li class='note'>You do not need to execute {@link InputStream#close()} on the response body to consume the response.
362    * </ul>
363    *
364    * <h5 class='section'>Example:</h5>
365    * <p class='bjava'>
366    *  <jc>// Get the response code.
367    *  // No need to call close() on the RestResponse object.</jc>
368    *  <jk>int</jk> <jv>rc</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).complete().getResponseCode();
369    * </p>
370    *
371    * @return The response object.
372    * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt.
373    */
374   public RestResponse complete() throws RestCallException {
375      return run().consume();
376   }
377
378   /**
379    * Used in combination with {@link #cancellable(Cancellable)}.
380    *
381    * @return This object.
382    */
383   @Deprecated
384   public RestRequest completed() {
385      request.completed();
386      return this;
387   }
388
389   /**
390    * Same as {@link #complete()} but allows you to run the call asynchronously.
391    *
392    * <h5 class='section'>Example:</h5>
393    * <p class='bjava'>
394    *    Future&lt;RestResponse&gt; <jv>future</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).completeFuture();
395    *
396    *    <jc>// Do some other stuff</jc>
397    *
398    *    <jk>int</jk> <jv>rc</jv> = <jv>future</jv>.get().getResponseStatus();
399    * </p>
400    *
401    * <h5 class='section'>Notes:</h5><ul>
402    *    <li class='note'>Use the {@link RestClient.Builder#executorService(ExecutorService, boolean)} method to customize the
403    *       executor service used for creating {@link Future Futures}.
404    *    <li class='note'>You do not need to execute {@link InputStream#close()} on the response body to consume the response.
405    * </ul>
406    *
407    * @return The HTTP status code.
408    * @throws RestCallException If the executor service was not defined.
409    */
410   public Future<RestResponse> completeFuture() throws RestCallException {
411      return client.getExecutorService().submit(this::complete);
412   }
413
414   /**
415    * Sets the actual request configuration.
416    *
417    * @param value The new value.
418    *    <br>Can be <jk>null</jk> (default configuration will be used).
419    * @return This object.
420    */
421   public RestRequest config(RequestConfig value) {
422      request.setConfig(value);
423      return this;
424   }
425
426   /**
427    * Checks if a certain header is present in this message.
428    *
429    * Header values are ignored.
430    *
431    * @param name The header name to check for.
432    *    <br>Cannot be <jk>null</jk>.
433    * @return <jk>true</jk> if at least one header with this name is present.
434    */
435   @Override /* Overridden from HttpMessage */
436   public boolean containsHeader(String name) {
437      return headerData.contains(name);
438   }
439
440   /**
441    * Sets the body of this request.
442    *
443    * @param value
444    *    The input to be sent to the REST resource (only valid for PUT/POST/PATCH) requests.
445    *    <br>Can be of the following types:
446    *    <ul class='spaced-list'>
447    *       <li>
448    *          {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource.
449    *       <li>
450    *          {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource.
451    *       <li>
452    *          {@link HttpResource} - Raw contents will be serialized to remote resource.  Additional headers and media type will be set on request.
453    *       <li>
454    *          {@link HttpEntity}/{@link BasicHttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient.
455    *       <li>
456    *          {@link Object} - POJO to be converted to text using the {@link Serializer} registered with the
457    *          {@link RestClient}.
458    *       <li>
459    *          {@link PartList} - Converted to a URL-encoded FORM post.
460    *       <li>
461    *          A {@link Supplier} of anything on this list.
462    *    </ul>
463    *    <br>Can be <jk>null</jk> (no body will be sent).
464    * @return This object.
465    */
466   public RestRequest content(Object value) {
467      content = value;
468      return this;
469   }
470
471   /**
472    * Sets the body of this request.
473    *
474    * @param input
475    *    The input to be sent to the REST resource (only valid for PUT/POST/PATCH) requests.
476    *    <br>Can be of the following types:
477    *    <ul class='spaced-list'>
478    *       <li>
479    *          {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource.
480    *       <li>
481    *          {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource.
482    *       <li>
483    *          {@link HttpResource} - Raw contents will be serialized to remote resource.  Additional headers and media type will be set on request.
484    *       <li>
485    *          {@link HttpEntity}/{@link BasicHttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient.
486    *       <li>
487    *          {@link Object} - POJO to be converted to text using the {@link Serializer} registered with the
488    *          {@link RestClient}.
489    *       <li>
490    *          {@link PartList} - Converted to a URL-encoded FORM post.
491    *       <li>
492    *          A {@link Supplier} of anything on this list.
493    *    </ul>
494    * @param schema The schema object that defines the format of the output.
495    *    <ul>
496    *       <li>If <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.
497    *       <li>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}).
498    *    </ul>
499    * @return This object.
500    */
501   public RestRequest content(Object input, HttpPartSchema schema) {
502      this.content = input;
503      this.contentSchema = schema;
504      return this;
505   }
506
507   /**
508    * Sets the body of this request as straight text bypassing the serializer.
509    *
510    * <p class='bjava'>
511    *    <jv>client</jv>
512    *       .put(<js>"/foo"</js>)
513    *       .content(<jk>new</jk> StringReader(<js>"foo"</js>))
514    *       .contentType(<js>"text/foo"</js>)
515    *       .run();
516    *
517    * <jv>client</jv>
518    *       .put(<js>"/foo"</js>)
519    *       .bodyString(<js>"foo"</js>)
520    *       .run();
521    * </p>
522    *
523    * <p>
524    * Note that this is different than the following which will serialize <l>foo</l> as a JSON string <l>"foo"</l>.
525    * <p class='bjava'>
526    *    <jv>client</jv>
527    *       .put(<js>"/foo"</js>)
528    *       .json()
529    *       .content(<js>"foo"</js>)
530    *       .run();
531    * </p>
532    *
533    * @param input
534    *    The input to be sent to the REST resource (only valid for PUT/POST/PATCH) requests.
535    * @return This object.
536    * @throws RestCallException If a retry was attempted, but the entity was not repeatable.
537    */
538   public RestRequest contentString(Object input) throws RestCallException {
539      return content(input == null ? null : new StringReader(s(input)));
540   }
541
542   /**
543    * Sets the value for the <c>Content-Type</c> request header.
544    *
545    * <p>
546    * This overrides the media type specified on the serializer, but is overridden by calling
547    * <code>header(<js>"Content-Type"</js>, value);</code>
548    *
549    * @param value The new header value.
550    *    <br>Can be <jk>null</jk> (header will not be set).
551    * @return This object.
552    * @throws RestCallException Invalid input.
553    */
554   public RestRequest contentType(String value) throws RestCallException {
555      return header(ContentType.of(value));
556   }
557
558   /**
559    * Override the context to use for the execution.
560    *
561    * @param context The context to use for the execution, or <jk>null</jk> to use the default context.
562    * @return This object.
563    */
564   public RestRequest context(HttpContext context) {
565      this.context = context;
566      return this;
567   }
568
569   /**
570    * Sets <c>Debug: value</c> header on this request.
571    *
572    * @return This object.
573    * @throws RestCallException Invalid input.
574    */
575   public RestRequest debug() throws RestCallException {
576      header("Debug", true);
577      return this;
578   }
579
580   /**
581    * Allows you to override what status codes are considered error codes that would result in a {@link RestCallException}.
582    *
583    * <p>
584    * The default error code predicate is: <code>x -&gt; x &gt;= 400</code>.
585    *
586    * @param value The new predicate for calculating error codes.
587    *    <br>Cannot be <jk>null</jk>.
588    * @return This object.
589    */
590   public RestRequest errorCodes(Predicate<Integer> value) {
591      errorCodes = assertArgNotNull("value", value);
592      return this;
593   }
594
595   /**
596    * Appends multiple form-data parameters to the request.
597    *
598    * <h5 class='section'>Example:</h5>
599    * <p class='bjava'>
600    *    <jc>// Appends two form-data parameters to the request.</jc>
601    *    <jv>client</jv>
602    *       .get(<jsf>URI</jsf>)
603    *       .formData(
604    *          BasicStringPart.<jsm>of</jsm>(<js>"foo"</js>, <js>"bar"</js>),
605    *          BasicBooleanPart.<jsm>of</jsm>(<js>"baz"</js>, <jk>true</jk>)
606    *       )
607    *       .run();
608    * </p>
609    *
610    * @param parts
611    *    The parameters to set.
612    *    <jk>null</jk> values are ignored.
613    * @return This object.
614    */
615   public RestRequest formData(NameValuePair...parts) {
616      formData.append(parts);
617      return this;
618   }
619
620   /**
621    * Adds a form-data parameter to the request body.
622    *
623    * <h5 class='section'>Example:</h5>
624    * <p class='bjava'>
625    *    <jc>// Adds form data parameter "foo=bar".</jc>
626    *    <jv>client</jv>
627    *       .formPost(<jsf>URI</jsf>)
628    *       .formData(<js>"foo"</js>, <js>"bar"</js>)
629    *       .run();
630    * </p>
631    *
632    * @param name
633    *    The parameter name.
634    *    <br>Cannot be <jk>null</jk> or empty (parameter will not be created).
635    * @param value
636    *    The parameter value.
637    *    <br>Non-string values are converted to strings using the {@link HttpPartSerializer} defined on the client.
638    *    <br>Can be <jk>null</jk>.
639    * @return This object.
640    */
641   public RestRequest formData(String name, Object value) {
642      formData.append(createPart(FORMDATA, name, value));
643      return this;
644   }
645
646   /**
647    * Appends multiple form-data parameters to the request from properties defined on a Java bean.
648    *
649    * <h5 class='section'>Example:</h5>
650    * <p class='bjava'>
651    *    <jk>public class</jk> MyFormData {
652    *       <jk>public</jk> String getFooBar() { <jk>return</jk> <js>"baz"</js>; }
653    *       <jk>public</jk> Integer getQux() { <jk>return</jk> 123; }
654    *    }
655    *
656    *    <jc>// Appends form data "fooBar=baz&amp;qux=123".</jc>
657    *    <jv>client</jv>
658    *       .get(<jsf>URI</jsf>)
659    *       .formDataBean(<jk>new</jk> MyFormData())
660    *       .run();
661    * </p>
662    *
663    * @param value The bean containing the properties to set as form-data parameter values.
664    *    <br>Cannot be <jk>null</jk>.
665    * @return This object.
666    */
667   public RestRequest formDataBean(Object value) {
668      assertArg(isBean(assertArgNotNull("value", value)), "Object passed into formDataBean(Object) is not a bean.");
669      var b = formData;
670      toBeanMap(value).forEach((k, v) -> b.append(createPart(FORMDATA, k, v)));
671      return this;
672   }
673
674   /**
675    * Adds form-data parameters as the entire body of the request.
676    *
677    * <h5 class='section'>Example:</h5>
678    * <p class='bjava'>
679    *    <jc>// Creates form data "foo=bar&amp;baz=qux".</jc>
680    *    <jv>client</jv>
681    *       .formPost(<jsf>URI</jsf>)
682    *       .formDataCustom(<js>"foo=bar&amp;baz=qux"</js>)
683    *       .run();
684    *
685    *    <jc>// Creates form data "foo=bar&amp;baz=qux" using StringEntity.</jc>
686    *    <jv>client</jv>
687    *       .formPost(<jsf>URI</jsf>)
688    *       .formDataCustom(<jk>new</jk> StringEntity(<js>"foo=bar&amp;baz=qux"</js>,<js>"application/x-www-form-urlencoded"</js>))
689    *       .run();
690    *
691    *    <jc>// Creates form data "foo=bar&amp;baz=qux" using StringEntity and body().</jc>
692    *    <jv>client</jv>
693    *       .formPost(<jsf>URI</jsf>)
694    *       .content(<jk>new</jk> StringEntity(<js>"foo=bar&amp;baz=qux"</js>,<js>"application/x-www-form-urlencoded"</js>))
695    *       .run();
696    * </p>
697    *
698    * @param value The parameter value.
699    *    <br>Can be any of the following types:
700    *    <ul class='spaced-list'>
701    *       <li>
702    *          {@link CharSequence}
703    *       <li>
704    *          {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource.
705    *       <li>
706    *          {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource.
707    *       <li>
708    *          {@link HttpResource} - Raw contents will be serialized to remote resource.  Additional headers and media type will be set on request.
709    *       <li>
710    *          {@link HttpEntity}/{@link BasicHttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient.
711    *       <li>
712    *          {@link Object} - POJO to be converted to text using the {@link Serializer} registered with the
713    *          {@link RestClient}.
714    *       <li>
715    *          {@link PartList} - Converted to a URL-encoded FORM post.
716    *    </ul>
717    *    <br>Can be <jk>null</jk> (no body will be sent).
718    * @return This object.
719    */
720   public RestRequest formDataCustom(Object value) {
721      header(ContentType.APPLICATION_FORM_URLENCODED);
722      content(value instanceof CharSequence ? new StringReader(value.toString()) : value);
723      return this;
724   }
725
726   /**
727    * Adds form-data parameters to the request body using free-form key/value pairs.
728    *
729    * <h5 class='section'>Example:</h5>
730    * <p class='bjava'>
731    *    <jc>// Creates form data "key1=val1&amp;key2=val2".</jc>
732    *    <jv>client</jv>
733    *       .formPost(<jsf>URI</jsf>)
734    *       .formDataPairs(<js>"key1"</js>,<js>"val1"</js>,<js>"key2"</js>,<js>"val2"</js>)
735    *       .run();
736    * </p>
737    *
738    * @param pairs The form-data key/value pairs.
739    *    <ul>
740    *       <li>Values can be any POJO.
741    *       <li>Values converted to a string using the configured part serializer.
742    *    </ul>
743    *    <br>Cannot be <jk>null</jk>.
744    *    <br>Must have an even number of elements (key/value pairs).
745    *    <br>Null keys are ignored (parameter will not be created).
746    *    <br>Null values are allowed.
747    * @return This object.
748    * @throws RestCallException Invalid input.
749    */
750   public RestRequest formDataPairs(String...pairs) throws RestCallException {
751      assertArg(pairs.length % 2 == 0, "Odd number of parameters passed into formDataPairs(String...)");
752      var b = formData;
753      for (var i = 0; i < pairs.length; i += 2)
754         b.append(pairs[i], pairs[i + 1]);
755      return this;
756   }
757
758   /**
759    * Returns all the headers of this message.
760    *
761    * Headers are ordered in the sequence they will be sent over a connection.
762    *
763    * @return All the headers of this message
764    */
765   @Override /* Overridden from HttpMessage */
766   public Header[] getAllHeaders() { return headerData.getAll(); }
767
768   /**
769    * Returns the actual request configuration.
770    *
771    * @return The actual request configuration.
772    */
773   @Override /* Overridden from Configurable */
774   public RequestConfig getConfig() { return request.getConfig(); }
775
776   /**
777    * Returns the first header with a specified name of this message.
778    *
779    * Header values are ignored.
780    * <br>If there is more than one matching header in the message the first element of {@link #getHeaders(String)} is returned.
781    * <br>If there is no matching header in the message <jk>null</jk> is returned.
782    *
783    * @param name The name of the header to return.
784    *    <br>Cannot be <jk>null</jk>.
785    * @return The first header whose name property equals name or <jk>null</jk> if no such header could be found.
786    */
787   @Override /* Overridden from HttpMessage */
788   public Header getFirstHeader(String name) {
789      return headerData.getFirst(name).orElse(null);
790   }
791
792   /**
793    * Returns the form data for the request.
794    *
795    * @return An immutable list of form data to send on the request.
796    */
797   public PartList getFormData() { return formData; }
798
799   /**
800    * Returns the header data for the request.
801    *
802    * @return An immutable list of headers to send on the request.
803    */
804   public HeaderList getHeaders() { return headerData; }
805
806   /**
807    * Returns all the headers with a specified name of this message.
808    *
809    * Header values are ignored.
810    * <br>Headers are ordered in the sequence they will be sent over a connection.
811    *
812    * @param name The name of the headers to return.
813    *    <br>Cannot be <jk>null</jk>.
814    * @return The headers whose name property equals name.
815    */
816   @Override /* Overridden from HttpMessage */
817   public Header[] getHeaders(String name) {
818      return headerData.getAll(name);
819   }
820
821   /**
822    * Returns the body of this request.
823    *
824    * @return The body of this request, or <jk>null</jk> if it doesn't have a body.
825    */
826   public HttpEntity getHttpEntity() { return hasHttpEntity() ? ((HttpEntityEnclosingRequestBase)request).getEntity() : null; }
827
828   /**
829    * Returns the last header with a specified name of this message.
830    *
831    * Header values are ignored.
832    * <br>If there is more than one matching header in the message the last element of {@link #getHeaders(String)} is returned.
833    * <br>If there is no matching header in the message null is returned.
834    *
835    * @param name The name of the header to return.
836    *    <br>Cannot be <jk>null</jk>.
837    * @return The last header whose name property equals name or <jk>null</jk> if no such header could be found.
838    */
839   @Override /* Overridden from HttpMessage */
840   public Header getLastHeader(String name) {
841      return headerData.getLast(name).orElse(null);
842   }
843
844   /**
845    * Returns the HTTP method this request uses, such as GET, PUT, POST, or other.
846    *
847    * @return The HTTP method this request uses, such as GET, PUT, POST, or other.
848    */
849   @Override /* Overridden from HttpUriRequest */
850   public String getMethod() { return request.getMethod(); }
851
852   /**
853    * Returns the parameters effective for this message as set by {@link #setParams(HttpParams)}.
854    *
855    * @return The parameters effective for this message as set by {@link #setParams(HttpParams)}.
856    * @deprecated Use constructor parameters of configuration API provided by HttpClient.
857    */
858   @Override /* Overridden from HttpMessage */
859   @Deprecated
860   public HttpParams getParams() { return request.getParams(); }
861
862   /**
863    * Returns the path data for the request.
864    *
865    * @return An immutable list of path data to send on the request.
866    */
867   public PartList getPathData() { return pathData; }
868
869   /**
870    * Returns the protocol version this message is compatible with.
871    *
872    * @return The protocol version.
873    */
874   @Override /* Overridden from HttpMessage */
875   public ProtocolVersion getProtocolVersion() { return request.getProtocolVersion(); }
876
877   /**
878    * Returns the query data for the request.
879    *
880    * @return An immutable list of query data to send on the request.
881    */
882   public PartList getQueryData() { return queryData; }
883
884   /**
885    * Returns the request line of this request.
886    *
887    * @return The request line.
888    */
889   @Override /* Overridden from HttpRequest */
890   public RequestLine getRequestLine() { return request.getRequestLine(); }
891
892   /**
893    * A shortcut for calling <c>run().getContent().as(<js>type</js>)</c>.
894    *
895    * @param type The object type to create.
896    *    <br>Cannot be <jk>null</jk>.
897    * @param <T> The object type to create.
898    * @see ResponseContent#as(Class)
899    * @return The response content as a simple string.
900    * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt.
901    */
902   public <T> T getResponse(Class<T> type) throws RestCallException {
903      return run().getContent().as(type);
904   }
905
906   /**
907    * A shortcut for calling <c>run().getContent().as(<js>type</js>,<js>args</js>)</c>.
908    *
909    * @param <T>
910    *    The object type to create.
911    * @param type
912    *    The object type to create.
913    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
914    *    <br>Cannot be <jk>null</jk>.
915    * @param args
916    *    The type arguments of the class if it's a collection or map.
917    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
918    *    <br>Ignored if the main type is not a map or collection.
919    *    <br>Can contain <jk>null</jk> values (ignored).
920    * @see ResponseContent#as(Type,Type...)
921    * @return The response content as a simple string.
922    * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt.
923    */
924   public <T> T getResponse(Type type, Type...args) throws RestCallException {
925      return run().getContent().as(type, args);
926   }
927
928   /**
929    * A shortcut for calling <c>run().getContent().asString()</c>.
930    *
931    * @return The response content as a simple string.
932    * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt.
933    */
934   public String getResponseAsString() throws RestCallException { return run().getContent().asString(); }
935
936   /**
937    * Returns the original request URI.
938    *
939    * <h5 class='section'>Notes:</h5><ul>
940    *    <li class='note'>URI remains unchanged in the course of request execution and is not updated if the request is redirected to another location.
941    * </ul>
942    *
943    * @return The original request URI.
944    */
945   @Override /* Overridden from HttpUriRequest */
946   public URI getURI() { return request.getURI(); }
947
948   /**
949    * Returns <jk>true</jk> if this request has a body.
950    *
951    * @return <jk>true</jk> if this request has a body.
952    */
953   public boolean hasHttpEntity() {
954      return request instanceof HttpEntityEnclosingRequestBase;
955   }
956
957   /**
958    * Appends a header to the request.
959    *
960    * <h5 class='section'>Example:</h5>
961    * <p class='bjava'>
962    *    <jc>// Adds header "Foo: bar".</jc>
963    *    <jv>client</jv>
964    *       .get(<jsf>URI</jsf>)
965    *       .header(Accept.<jsf>TEXT_XML</jsf>)
966    *       .run();
967    * </p>
968    *
969    * @param part
970    *    The parameter to set.
971    *    <jk>null</jk> values are ignored.
972    * @return This object.
973    */
974   public RestRequest header(Header part) {
975      return headers(part);
976   }
977
978   /**
979    * Appends a header to the request.
980    *
981    * <h5 class='section'>Example:</h5>
982    * <p class='bjava'>
983    *    <jc>// Adds header "Foo: bar".</jc>
984    *    <jv>client</jv>
985    *       .get(<jsf>URI</jsf>)
986    *       .header(<js>"Foo"</js>, <js>"bar"</js>)
987    *       .run();
988    * </p>
989    *
990    * @param name
991    *    The parameter name.
992    * @param value
993    *    The parameter value.
994    *    <br>Non-string values are converted to strings using the {@link HttpPartSerializer} defined on the client.
995    * @return This object.
996    */
997   public RestRequest header(String name, Object value) {
998      headerData.append(createHeader(name, value));
999      return this;
1000   }
1001
1002   /**
1003    * Returns an iterator of all the headers.
1004    *
1005    * @return Iterator that returns {@link Header} objects in the sequence they are sent over a connection.
1006    */
1007   @Override /* Overridden from HttpMessage */
1008   public HeaderIterator headerIterator() {
1009      return headerData.headerIterator();
1010   }
1011
1012   /**
1013    * Returns an iterator of the headers with a given name.
1014    *
1015    * @param name the name of the headers over which to iterate, or <jk>null</jk> for all headers.
1016    * @return Iterator that returns {@link Header} objects with the argument name in the sequence they are sent over a connection.
1017    */
1018   @Override /* Overridden from HttpMessage */
1019   public HeaderIterator headerIterator(String name) {
1020      return headerData.headerIterator(name);
1021   }
1022
1023   /**
1024    * Appends multiple headers to the request using freeform key/value pairs.
1025    *
1026    * <h5 class='section'>Example:</h5>
1027    * <p class='bjava'>
1028    *    <jc>// Adds headers "Foo: bar" and "Baz: qux".</jc>
1029    *    <jv>client</jv>
1030    *       .get(<jsf>URI</jsf>)
1031    *       .headerPairs(<js>"Foo"</js>,<js>"bar"</js>,<js>"Baz"</js>,<js>"qux"</js>)
1032    *       .run();
1033    * </p>
1034    *
1035    * @param pairs The header key/value pairs.
1036    *    <br>Cannot be <jk>null</jk>.
1037    *    <br>Must have an even number of elements (key/value pairs).
1038    *    <br>Null keys are ignored (header will not be created).
1039    *    <br>Null values are allowed.
1040    * @return This object.
1041    */
1042   public RestRequest headerPairs(String...pairs) {
1043      assertArg(pairs.length % 2 == 0, "Odd number of parameters passed into headerPairs(String...)");
1044      var b = headerData;
1045      for (var i = 0; i < pairs.length; i += 2)
1046         b.append(pairs[i], pairs[i + 1]);
1047      return this;
1048   }
1049
1050   /**
1051    * Appends multiple headers to the request.
1052    *
1053    * <h5 class='section'>Example:</h5>
1054    * <p class='bjava'>
1055    *    <jc>// Appends two headers to the request.</jc>
1056    *    <jv>client</jv>
1057    *       .get(<jsf>URI</jsf>)
1058    *       .headers(
1059    *          BasicHeader.<jsm>of</jsm>(<js>"Foo"</js>, <js>"bar"</js>),
1060    *          Accept.<jsf>TEXT_XML</jsf>
1061    *       )
1062    *       .run();
1063    * </p>
1064    *
1065    * @param parts
1066    *    The parameters to set.
1067    *    <jk>null</jk> values are ignored.
1068    * @return This object.
1069    */
1070   public RestRequest headers(Header...parts) {
1071      headerData.append(parts);
1072      return this;
1073   }
1074
1075   /**
1076    * Appends multiple headers to the request from properties defined on a Java bean.
1077    *
1078    * <p>
1079    * Uses {@link PropertyNamerDUCS} for resolving the header names from property names.
1080    *
1081    * <h5 class='section'>Example:</h5>
1082    * <p class='bjava'>
1083    *    <ja>@Bean</ja>
1084    *    <jk>public class</jk> MyHeaders {
1085    *       <jk>public</jk> String getFooBar() { <jk>return</jk> <js>"baz"</js>; }
1086    *       <jk>public</jk> Integer getQux() { <jk>return</jk> 123; }
1087    *    }
1088    *
1089    *    <jc>// Appends headers "Foo-Bar: baz" and "Qux: 123".</jc>
1090    *    <jv>client</jv>
1091    *       .get(<jsf>URI</jsf>)
1092    *       .headersBean(<jk>new</jk> MyHeaders())
1093    *       .run();
1094    * </p>
1095    *
1096    * @param value The bean containing the properties to set as header values.
1097    *    <br>Cannot be <jk>null</jk>.
1098    * @return This object.
1099    */
1100   public RestRequest headersBean(Object value) {
1101      assertArg(isBean(assertArgNotNull("value", value)), "Object passed into headersBean(Object) is not a bean.");
1102      var b = headerData;
1103      toBeanMap(value, PropertyNamerDUCS.INSTANCE).forEach((k, v) -> b.append(createHeader(k, v)));
1104      return this;
1105   }
1106
1107   /**
1108    * Convenience method for specifying HTML as the marshalling transmission media type for this request only.
1109    *
1110    * <p>
1111    * POJOs are converted to HTML without any sort of doc wrappers.
1112    *
1113    * <p>
1114    *    {@link HtmlSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
1115    *    <ul>
1116    *       <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClient.Builder#sortCollections()}) or
1117    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
1118    *    </ul>
1119    * <p>
1120    *    {@link HtmlParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
1121    *    <ul>
1122    *       <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClient.Builder#strict()}) or
1123    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
1124    *    </ul>
1125    * <p>
1126    *    <c>Accept</c> request header will be set to <js>"text/html"</js> unless overridden
1127    *       by {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(String)}.
1128    * <p>
1129    *    <c>Content-Type</c> request header will be set to <js>"text/html"</js> unless overridden
1130    *       by {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(String)}.
1131    * <p>
1132    *    Identical to calling <c>serializer(HtmlSerializer.<jk>class</jk>).parser(HtmlParser.<jk>class</jk>)</c>.
1133    *
1134    * @return This object.
1135    */
1136   public RestRequest html() {
1137      return serializer(HtmlSerializer.class).parser(HtmlParser.class);
1138   }
1139
1140   /**
1141    * Convenience method for specifying HTML DOC as the marshalling transmission media type for this request only.
1142    *
1143    * <p>
1144    * POJOs are converted to fully renderable HTML pages.
1145    *
1146    * <p>
1147    *    {@link HtmlDocSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
1148    *    <ul>
1149    *       <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClient.Builder#sortCollections()}) or
1150    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
1151    *    </ul>
1152    * <p>
1153    *    {@link HtmlParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
1154    *    <ul>
1155    *       <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClient.Builder#strict()}) or
1156    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
1157    *    </ul>
1158    * <p>
1159    *    <c>Accept</c> request header will be set to <js>"text/html"</js> unless overridden
1160    *       by {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(String)}.
1161    * <p>
1162    *    <c>Content-Type</c> request header will be set to <js>"text/html"</js> unless overridden
1163    *       by {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(String)}.
1164    * <p>
1165    *    Identical to calling <c>serializer(HtmlDocSerializer.<jk>class</jk>).parser(HtmlParser.<jk>class</jk>)</c>.
1166    *
1167    * @return This object.
1168    */
1169   public RestRequest htmlDoc() {
1170      return serializer(HtmlDocSerializer.class).parser(HtmlParser.class);
1171   }
1172
1173   /**
1174    * Convenience method for specifying Stripped HTML DOC as the marshalling transmission media type for this request only.
1175    *
1176    * <p>
1177    * Same as {@link #htmlDoc()} but without the header and body tags and page title and description.
1178    *
1179    * <p>
1180    *    {@link HtmlStrippedDocSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
1181    *    <ul>
1182    *       <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClient.Builder#sortCollections()}) or
1183    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
1184    *    </ul>
1185    * <p>
1186    *    {@link HtmlParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
1187    *    <ul>
1188    *       <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClient.Builder#strict()}) or
1189    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
1190    *    </ul>
1191    * <p>
1192    *    <c>Accept</c> request header will be set to <js>"text/html+stripped"</js> unless overridden
1193    *       by {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(String)}.
1194    * <p>
1195    *    <c>Content-Type</c> request header will be set to <js>"text/html+stripped"</js> unless overridden
1196    *       by {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(String)}.
1197    * <p>
1198    *    Identical to calling <c>serializer(HtmlStrippedDocSerializer.<jk>class</jk>).parser(HtmlParser.<jk>class</jk>)</c>.
1199    *
1200    * @return This object.
1201    */
1202   public RestRequest htmlStrippedDoc() {
1203      return serializer(HtmlStrippedDocSerializer.class).parser(HtmlParser.class);
1204   }
1205
1206   /**
1207    * Prevent {@link RestCallException RestCallExceptions} from being thrown when HTTP status 400+ is encountered.
1208    *
1209    * <p>
1210    * This overrides the <l>ignoreErrors</l> property on the client.
1211    *
1212    * @return This object.
1213    */
1214   public RestRequest ignoreErrors() {
1215      this.ignoreErrors = true;
1216      return this;
1217   }
1218
1219   /**
1220    * Add one or more interceptors for this call only.
1221    *
1222    * @param interceptors The interceptors to add to this call.
1223    *    <br>Cannot contain <jk>null</jk> values.
1224    * @return This object.
1225    * @throws RestCallException If init method on interceptor threw an exception.
1226    */
1227   public RestRequest interceptors(RestCallInterceptor...interceptors) throws RestCallException {
1228      assertArgNoNulls("interceptors", interceptors);
1229      try {
1230         for (var i : interceptors) {
1231            this.interceptors.add(i);
1232            i.onInit(this);
1233         }
1234      } catch (RuntimeException | RestCallException e) {
1235         throw e;
1236      } catch (Exception e) {
1237         throw new RestCallException(null, e, "Interceptor threw an exception on init.");
1238      }
1239
1240      return this;
1241   }
1242
1243   @Override /* Overridden from HttpUriRequest */
1244   public boolean isAborted() { return request.isAborted(); }
1245
1246   /**
1247    * Returns <jk>true</jk> if debug mode is currently enabled.
1248    */
1249   @Override
1250   public boolean isDebug() { return headerData.get("Debug", Boolean.class).orElse(false); }
1251
1252   /**
1253    * Convenience method for specifying JSON as the marshalling transmission media type for this request only.
1254    *
1255    * <p>
1256    * {@link JsonSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
1257    *    <ul>
1258    *       <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClient.Builder#sortCollections()}) or
1259    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
1260    *    </ul>
1261    * <p>
1262    *    {@link JsonParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
1263    *    <ul>
1264    *       <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClient.Builder#strict()}) or
1265    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
1266    *    </ul>
1267    * <p>
1268    *    <c>Accept</c> request header will be set to <js>"application/json"</js> unless overridden
1269    *       by {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(String)}.
1270    * <p>
1271    *    <c>Content-Type</c> request header will be set to <js>"application/json"</js> unless overridden
1272    *       {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(String)}.
1273    * <p>
1274    *    Identical to calling <c>serializer(JsonSerializer.<jk>class</jk>).parser(JsonParser.<jk>class</jk>)</c>.
1275    *
1276    * @return This object.
1277    */
1278   public RestRequest json() {
1279      return serializer(JsonSerializer.class).parser(JsonParser.class);
1280   }
1281
1282   /**
1283    * Convenience method for specifying Simplified JSON as the marshalling transmission media type for this request only.
1284    *
1285    * <p>
1286    * Simplified JSON is typically useful for automated tests because you can do simple string comparison of results
1287    * without having to escape lots of quotes.
1288    *
1289    * <p>
1290    *    {@link Json5Serializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
1291    *    <ul>
1292    *       <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClient.Builder#sortCollections()}) or
1293    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
1294    *    </ul>
1295    * <p>
1296    *    {@link Json5Parser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
1297    *    <ul>
1298    *       <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClient.Builder#strict()}) or
1299    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
1300    *    </ul>
1301    * <p>
1302    *    <c>Accept</c> request header will be set to <js>"application/json"</js> unless overridden
1303    *       by {@link #header(String,Object)} or {@link #accept(String)}, or per-request via {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(String)}.
1304    * <p>
1305    *    <c>Content-Type</c> request header will be set to <js>"application/json+simple"</js> unless overridden
1306    *       by {@link #header(String,Object)} or {@link #contentType(String)}, or per-request via {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(String)}.
1307    * <p>
1308    *    Can be combined with other marshaller setters such as {@link #xml()} to provide support for multiple languages.
1309    *    <ul>
1310    *       <li>When multiple languages are supported, the <c>Accept</c> and <c>Content-Type</c> headers control which marshallers are used, or uses the
1311    *       last-enabled language if the headers are not set.
1312    *    </ul>
1313    * <p>
1314    *    Identical to calling <c>serializer(Json5Serializer.<jk>class</jk>).parser(Json5Parser.<jk>class</jk>)</c>.
1315    *
1316    * @return This object.
1317    */
1318   public RestRequest json5() {
1319      return serializer(Json5Serializer.class).parser(Json5Parser.class);
1320   }
1321
1322   /**
1323    * Logs a message.
1324    *
1325    * @param level The log level.
1326    *    <br>Cannot be <jk>null</jk>.
1327    * @param msg The message with {@link MessageFormat}-style arguments.
1328    *    <br>Cannot be <jk>null</jk>.
1329    * @param args The arguments.
1330    *    <br>Can contain <jk>null</jk> values.
1331    * @return This object.
1332    */
1333   public RestRequest log(Level level, String msg, Object...args) {
1334      client.log(level, msg, args);
1335      return this;
1336   }
1337
1338   /**
1339    * Logs a message.
1340    *
1341    * @param level The log level.
1342    *    <br>Cannot be <jk>null</jk>.
1343    * @param t The throwable cause.
1344    *    <br>Can be <jk>null</jk>.
1345    * @param msg The message with {@link MessageFormat}-style arguments.
1346    *    <br>Cannot be <jk>null</jk>.
1347    * @param args The arguments.
1348    *    <br>Can contain <jk>null</jk> values.
1349    * @return This object.
1350    */
1351   public RestRequest log(Level level, Throwable t, String msg, Object...args) {
1352      client.log(level, t, msg, args);
1353      return this;
1354   }
1355
1356   /**
1357    * Shortcut for setting the <c>Accept</c> and <c>Content-Type</c> headers on a request.
1358    *
1359    * @param value The new header values.
1360    *    <br>Can be <jk>null</jk> (headers will not be set).
1361    * @return This object.
1362    * @throws RestCallException Invalid input.
1363    */
1364   public RestRequest mediaType(String value) throws RestCallException {
1365      return header(Accept.of(value)).header(ContentType.of(value));
1366   }
1367
1368   /**
1369    * Convenience method for specifying MessagePack as the marshalling transmission media type for this request only.
1370    *
1371    * <p>
1372    * MessagePack is a binary equivalent to JSON that takes up considerably less space than JSON.
1373    *
1374    * <p>
1375    *    {@link MsgPackSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
1376    *    <ul>
1377    *       <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClient.Builder#sortCollections()}) or
1378    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
1379    *    </ul>
1380    * <p>
1381    *    {@link MsgPackParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
1382    *    <ul>
1383    *       <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClient.Builder#strict()}) or
1384    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
1385    *    </ul>
1386    * <p>
1387    *    <c>Accept</c> request header will be set to <js>"octal/msgpack"</js> unless overridden
1388    *       by {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(String)}.
1389    * <p>
1390    *    <c>Content-Type</c> request header will be set to <js>"octal/msgpack"</js> unless overridden
1391    *       by {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(String)}.
1392    * <p>
1393    *    Identical to calling <c>serializer(MsgPackSerializer.<jk>class</jk>).parser(MsgPackParser.<jk>class</jk>)</c>.
1394    *
1395    * @return This object.
1396    */
1397   public RestRequest msgPack() {
1398      return serializer(MsgPackSerializer.class).parser(MsgPackParser.class);
1399   }
1400
1401   /**
1402    * When called, <c>No-Trace: true</c> is added to requests.
1403    *
1404    * <p>
1405    * This gives the opportunity for the servlet to not log errors on invalid requests.
1406    * This is useful for testing purposes when you don't want your log file to show lots of errors that are simply the
1407    * results of testing.
1408    *
1409    * @return This object.
1410    * @throws RestCallException Invalid input.
1411    */
1412   public RestRequest noTrace() throws RestCallException {
1413      return header(NoTrace.TRUE);
1414   }
1415
1416   /**
1417    * Convenience method for specifying OpenAPI as the marshalling transmission media type for this request only.
1418    *
1419    * <p>
1420    * OpenAPI is a language that allows serialization to formats that use {@link HttpPartSchema} objects to describe their structure.
1421    *
1422    * <p>
1423    *    {@link OpenApiSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
1424    *    <ul>
1425    *       <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClient.Builder#sortCollections()}) or
1426    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
1427    *       <li>Typically the {@link RestRequest#content(Object, HttpPartSchema)} method will be used to specify the body of the request with the
1428    *          schema describing it's structure.
1429    *    </ul>
1430    * <p>
1431    *    {@link OpenApiParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
1432    *    <ul>
1433    *       <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClient.Builder#strict()}) or
1434    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
1435    *       <li>Typically the {@link ResponseContent#schema(HttpPartSchema)} method will be used to specify the structure of the response body.
1436    *    </ul>
1437    * <p>
1438    *    <c>Accept</c> request header will be set to <js>"text/openapi"</js> unless overridden
1439    *       by {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(String)}.
1440    * <p>
1441    *    <c>Content-Type</c> request header will be set to <js>"text/openapi"</js> unless overridden
1442    *       by {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(String)}.
1443    * <p>
1444    *    Identical to calling <c>serializer(OpenApiSerializer.<jk>class</jk>).parser(OpenApiParser.<jk>class</jk>)</c>.
1445    *
1446    * @return This object.
1447    */
1448   public RestRequest openApi() {
1449      return serializer(OpenApiSerializer.class).parser(OpenApiParser.class);
1450   }
1451
1452   /**
1453    * Specifies the parser to use on the response body.
1454    *
1455    * <p>
1456    * Overrides the parsers specified on the {@link RestClient}.
1457    *
1458    * <p>
1459    *    The parser can be configured using any of the parser property setters (e.g. {@link RestClient.Builder#strict()}) or
1460    *    bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
1461    *
1462    * <p>
1463    * If the <c>Accept</c> header is not set on the request, it will be set to the media type of this parser.
1464    *
1465    * @param parser The parser used to parse POJOs from the body of the HTTP response.
1466    *    <br>Cannot be <jk>null</jk>.
1467    * @return This object.
1468    */
1469   public RestRequest parser(Class<? extends Parser> parser) {
1470      this.parser = client.getInstance(assertArgNotNull("parser", parser));
1471      return this;
1472   }
1473
1474   /**
1475    * Specifies the parser to use on the response body.
1476    *
1477    * <p>
1478    * Overrides the parsers specified on the {@link RestClient}.
1479    *
1480    * <p>
1481    *    The parser is not modified by any of the parser property setters (e.g. {@link RestClient.Builder#strict()}) or
1482    *    bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
1483    *
1484    * <p>
1485    * If the <c>Accept</c> header is not set on the request, it will be set to the media type of this parser.
1486    *
1487    * @param parser The parser used to parse POJOs from the body of the HTTP response.
1488    *    <br>Cannot be <jk>null</jk>.
1489    * @return This object.
1490    */
1491   public RestRequest parser(Parser parser) {
1492      this.parser = assertArgNotNull("parser", parser);
1493      return this;
1494   }
1495
1496   /**
1497    * Sets or replaces multiple path parameters on the request.
1498    *
1499    * <h5 class='section'>Example:</h5>
1500    * <p class='bjava'>
1501    *    <jc>// Appends two path parameters to the request.</jc>
1502    *    <jv>client</jv>
1503    *       .get(<jsf>URI</jsf>)
1504    *       .pathData(
1505    *          BasicStringPart.<jsm>of</jsm>(<js>"foo"</js>, <js>"bar"</js>),
1506    *          BasicBooleanPart.<jsm>of</jsm>(<js>"baz"</js>, <jk>true</jk>)
1507    *       )
1508    *       .run();
1509    * </p>
1510    *
1511    * @param parts
1512    *    The parameters to set.
1513    *    <jk>null</jk> values are ignored.
1514    * @return This object.
1515    */
1516   public RestRequest pathData(NameValuePair...parts) {
1517      pathData.set(parts);
1518      return this;
1519   }
1520
1521   /**
1522    * Sets or replaces a path parameter of the form <js>"{name}"</js> in the URI.
1523    *
1524    * <h5 class='section'>Example:</h5>
1525    * <p class='bjava'>
1526    *    <jc>// Sets path to "/bar".</jc>
1527    *    <jv>client</jv>
1528    *       .get(<js>"/{foo}"</js>)
1529    *       .pathData(<js>"foo"</js>, <js>"bar"</js>)
1530    *       .run();
1531    * </p>
1532    *
1533    * @param name
1534    *    The parameter name.
1535    *    <br>Cannot be <jk>null</jk> or empty (parameter will not be created).
1536    * @param value
1537    *    The parameter value.
1538    *    <br>Non-string values are converted to strings using the {@link HttpPartSerializer} defined on the client.
1539    *    <br>Can be <jk>null</jk>.
1540    * @return This object.
1541    */
1542   public RestRequest pathData(String name, Object value) {
1543      pathData.set(createPart(PATH, name, value));
1544      return this;
1545   }
1546
1547   /**
1548    * Sets multiple path parameters to the request from properties defined on a Java bean.
1549    *
1550    * <h5 class='section'>Example:</h5>
1551    * <p class='bjava'>
1552    *    <jk>public class</jk> MyPathVars {
1553    *       <jk>public</jk> String getFooBar() { <jk>return</jk> <js>"baz"</js>; }
1554    *       <jk>public</jk> Integer getQux() { <jk>return</jk> 123; }
1555    *    }
1556    *
1557    *    <jc>// Given path "/{fooBar}/{qux}/", gets converted to "/baz/123/".</jc>
1558    *    <jv>client</jv>
1559    *       .get(<jsf>URI</jsf>)
1560    *       .pathDataBean(<jk>new</jk> MyPathVars())
1561    *       .run();
1562    * </p>
1563    *
1564    * @param value The bean containing the properties to set as path parameter values.
1565    *    <br>Cannot be <jk>null</jk>.
1566    * @return This object.
1567    */
1568   public RestRequest pathDataBean(Object value) {
1569      assertArg(isBean(assertArgNotNull("value", value)), "Object passed into pathDataBean(Object) is not a bean.");
1570      var b = pathData;
1571      toBeanMap(value).forEach((k, v) -> b.set(createPart(PATH, k, v)));
1572      return this;
1573   }
1574
1575   /**
1576    * Replaces path parameters of the form <js>"{name}"</js> in the URI using free-form key/value pairs.
1577    *
1578    * <h5 class='section'>Example:</h5>
1579    * <p class='bjava'>
1580    *    <jc>// Sets path to "/baz/qux".</jc>
1581    *    <jv>client</jv>
1582    *       .get(<js>"/{foo}/{bar}"</js>)
1583    *       .pathDataPairs(
1584    *          <js>"foo"</js>,<js>"baz"</js>,
1585    *          <js>"bar"</js>,<js>"qux"</js>
1586    *       )
1587    *       .run();
1588    * </p>
1589    *
1590    * @param pairs The path key/value pairs.
1591    *    <ul>
1592    *       <li>Values can be any POJO.
1593    *       <li>Values converted to a string using the configured part serializer.
1594    *    </ul>
1595    *    <br>Cannot be <jk>null</jk>.
1596    *    <br>Must have an even number of elements (key/value pairs).
1597    *    <br>Null keys are ignored (parameter will not be created).
1598    *    <br>Null values are allowed.
1599    * @return This object.
1600    */
1601   public RestRequest pathDataPairs(String...pairs) {
1602      assertArg(pairs.length % 2 == 0, "Odd number of parameters passed into pathDataPairs(String...)");
1603      var b = pathData;
1604      for (var i = 0; i < pairs.length; i += 2)
1605         b.set(pairs[i], pairs[i + 1]);
1606      return this;
1607   }
1608
1609   /**
1610    * Convenience method for specifying Plain Text as the marshalling transmission media type for this request only.
1611    *
1612    * <p>
1613    * Plain text marshalling typically only works on simple POJOs that can be converted to and from strings using
1614    * swaps, swap methods, etc...
1615    *
1616    * <p>
1617    *    {@link PlainTextSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
1618    *    <ul>
1619    *       <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClient.Builder#sortCollections()}) or
1620    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
1621    *    </ul>
1622    * <p>
1623    *    {@link PlainTextParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
1624    *    <ul>
1625    *       <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClient.Builder#strict()}) or
1626    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
1627    *    </ul>
1628    * <p>
1629    *    <c>Accept</c> request header will be set to <js>"text/plain"</js> unless overridden
1630    *       by {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(String)}.
1631    * <p>
1632    *    <c>Content-Type</c> request header will be set to <js>"text/plain"</js> unless overridden
1633    *       by {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(String)}.
1634    * <p>
1635    *    Identical to calling <c>serializer(PlainTextSerializer.<jk>class</jk>).parser(PlainTextParser.<jk>class</jk>)</c>.
1636    *
1637    * @return This object.
1638    */
1639   public RestRequest plainText() {
1640      return serializer(PlainTextSerializer.class).parser(PlainTextParser.class);
1641   }
1642
1643   /**
1644    * Sets the protocol version for this request.
1645    *
1646    * @param version The protocol version for this request.
1647    *    <br>Can be <jk>null</jk> (default protocol version will be used).
1648    * @return This object.
1649    */
1650   public RestRequest protocolVersion(ProtocolVersion version) {
1651      request.setProtocolVersion(version);
1652      return this;
1653   }
1654
1655   /**
1656    * Adds a free-form custom query.
1657    *
1658    * <h5 class='section'>Example:</h5>
1659    * <p class='bjava'>
1660    *    <jc>// Adds query parameter "foo=bar&amp;baz=qux".</jc>
1661    *    <jv>client</jv>
1662    *       .get(<jsf>URI</jsf>)
1663    *       .queryCustom(<js>"foo=bar&amp;baz=qux"</js>)
1664    *       .run();
1665    * </p>
1666    *
1667    * @param value The parameter value.
1668    *    <br>Can be any of the following types:
1669    *    <ul>
1670    *       <li>
1671    *          {@link CharSequence}
1672    *       <li>
1673    *          {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource.
1674    *       <li>
1675    *          {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource.
1676    *       <li>
1677    *          {@link PartList} - Converted to a URL-encoded query.
1678    *    </ul>
1679    *    <br>Can be <jk>null</jk> (no custom query will be set).
1680    * @return This object.
1681    */
1682   public RestRequest queryCustom(Object value) {
1683      try {
1684         var q = (String)null;
1685         if (value instanceof Reader value2)
1686            q = read(value2);
1687         else if (value instanceof InputStream value2)
1688            q = read(value2);
1689         else
1690            q = s(value);  // Works for NameValuePairs.
1691         uriBuilder.setCustomQuery(q);
1692      } catch (IOException e) {
1693         throw rex(e, "Could not read custom query.");
1694      }
1695      return this;
1696   }
1697
1698   /**
1699    * Appends multiple query parameters to the request.
1700    *
1701    * <h5 class='section'>Example:</h5>
1702    * <p class='bjava'>
1703    *    <jc>// Appends two query parameters to the request.</jc>
1704    *    <jv>client</jv>
1705    *       .get(<jsf>URI</jsf>)
1706    *       .queryData(
1707    *          BasicStringPart.<jsm>of</jsm>(<js>"foo"</js>, <js>"bar"</js>),
1708    *          BasicBooleanPart.<jsm>of</jsm>(<js>"baz"</js>, <jk>true</jk>)
1709    *       )
1710    *       .run();
1711    * </p>
1712    *
1713    * @param parts
1714    *    The parameters to set.
1715    *    <jk>null</jk> values are ignored.
1716    * @return This object.
1717    */
1718   public RestRequest queryData(NameValuePair...parts) {
1719      queryData.append(parts);
1720      return this;
1721   }
1722
1723   /**
1724    * Appends a query parameter to the URI of the request.
1725    *
1726    * <h5 class='section'>Example:</h5>
1727    * <p class='bjava'>
1728    *    <jc>// Adds query parameter "foo=bar".</jc>
1729    *    <jv>client</jv>
1730    *       .get(<jsf>URI</jsf>)
1731    *       .queryData(<js>"foo"</js>, <js>"bar"</js>)
1732    *       .run();
1733    * </p>
1734    *
1735    * @param name
1736    *    The parameter name.
1737    *    <br>Cannot be <jk>null</jk> or empty (parameter will not be created).
1738    * @param value
1739    *    The parameter value.
1740    *    <br>Non-string values are converted to strings using the {@link HttpPartSerializer} defined on the client.
1741    *    <br>Can be <jk>null</jk>.
1742    * @return This object.
1743    */
1744   public RestRequest queryData(String name, Object value) {
1745      queryData.append(createPart(QUERY, name, value));
1746      return this;
1747   }
1748
1749   /**
1750    * Appends multiple query parameters to the request from properties defined on a Java bean.
1751    *
1752    * <h5 class='section'>Example:</h5>
1753    * <p class='bjava'>
1754    *    <jk>public class</jk> MyQuery {
1755    *       <jk>public</jk> String getFooBar() { <jk>return</jk> <js>"baz"</js>; }
1756    *       <jk>public</jk> Integer getQux() { <jk>return</jk> 123; }
1757    *    }
1758    *
1759    *    <jc>// Appends query "fooBar=baz&amp;qux=123".</jc>
1760    *    <jv>client</jv>
1761    *       .get(<jsf>URI</jsf>)
1762    *       .queryDataBean(<jk>new</jk> MyQuery())
1763    *       .run();
1764    * </p>
1765    *
1766    * @param value The bean containing the properties to set as query parameter values.
1767    *    <br>Cannot be <jk>null</jk>.
1768    * @return This object.
1769    */
1770   public RestRequest queryDataBean(Object value) {
1771      assertArg(isBean(assertArgNotNull("value", value)), "Object passed into queryDataBean(Object) is not a bean.");
1772      var b = queryData;
1773      toBeanMap(value).forEach((k, v) -> b.append(createPart(QUERY, k, v)));
1774      return this;
1775   }
1776
1777   /**
1778    * Adds query parameters to the URI query using free-form key/value pairs..
1779    *
1780    * <h5 class='section'>Example:</h5>
1781    * <p class='bjava'>
1782    *    <jc>// Adds query parameters "foo=bar&amp;baz=qux".</jc>
1783    *    <jv>client</jv>
1784    *       .get(<jsf>URI</jsf>)
1785    *       .queryDataPairs(<js>"foo"</js>,<js>"bar"</js>,<js>"baz"</js>,<js>"qux"</js>)
1786    *       .run();
1787    * </p>
1788    *
1789    * @param pairs The query key/value pairs.
1790    *    <ul>
1791    *       <li>Values can be any POJO.
1792    *       <li>Values converted to a string using the configured part serializer.
1793    *    </ul>
1794    *    <br>Cannot be <jk>null</jk>.
1795    *    <br>Must have an even number of elements (key/value pairs).
1796    *    <br>Null keys are ignored (parameter will not be created).
1797    *    <br>Null values are allowed.
1798    * @return This object.
1799    * @throws RestCallException Invalid input.
1800    */
1801   public RestRequest queryDataPairs(String...pairs) throws RestCallException {
1802      assertArg(pairs.length % 2 == 0, "Odd number of parameters passed into queryDataPairs(String...)");
1803      var b = queryData;
1804      for (var i = 0; i < pairs.length; i += 2)
1805         b.append(pairs[i], pairs[i + 1]);
1806      return this;
1807   }
1808
1809   /**
1810    * Removes a header from this message.
1811    *
1812    * @param header The header to remove.
1813    *    <br>Can be <jk>null</jk> (no-op).
1814    */
1815   @Override /* Overridden from HttpMessage */
1816   public void removeHeader(Header header) {
1817      headerData.remove(header);
1818   }
1819
1820   /**
1821    * Removes all headers with a certain name from this message.
1822    *
1823    * @param name The name of the headers to remove.
1824    *    <br>Cannot be <jk>null</jk>.
1825    */
1826   @Override /* Overridden from HttpMessage */
1827   public void removeHeaders(String name) {
1828      headerData.remove(name);
1829   }
1830
1831   /**
1832    * Rethrow any of the specified exception types if a matching <c>Exception-Name</c> header is found.
1833    *
1834    * <p>
1835    * Rethrown exceptions will be set on the caused-by exception of {@link RestCallException} when
1836    * thrown from the {@link #run()} method.
1837    *
1838    * <p>
1839    * Can be called multiple times to append multiple rethrows.
1840    *
1841    * @param values The classes to rethrow.
1842    *    <br>Cannot be <jk>null</jk>.
1843    *    <br>Null elements are ignored (only non-null classes that extend {@link Throwable} are added).
1844    * @return This object.
1845    */
1846   @SuppressWarnings("unchecked")
1847   public RestRequest rethrow(Class<?>...values) {
1848      if (rethrow == null)
1849         rethrow = list();
1850      for (var v : values) {
1851         if (nn(v) && Throwable.class.isAssignableFrom(v))
1852            rethrow.add((Class<? extends Throwable>)v);
1853      }
1854      return this;
1855   }
1856
1857   /**
1858    * Runs this request and returns the resulting response object.
1859    *
1860    * <h5 class='section'>Example:</h5>
1861    * <p class='bjava'>
1862    *    <jk>try</jk> {
1863    *       <jk>int</jk> <jv>rc</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).execute().getResponseStatus();
1864    *       <jc>// Succeeded!</jc>
1865    *    } <jk>catch</jk> (RestCallException <jv>e</jv>) {
1866    *       <jc>// Failed!</jc>
1867    *    }
1868    * </p>
1869    *
1870    * <h5 class='section'>Notes:</h5><ul>
1871    *    <li class='note'>Calling this method multiple times will return the same original response object.
1872    *    <li class='note'>You must close the returned object if you do not consume the response or execute a method that consumes
1873    *       the response.
1874    *    <li class='note'>If you are only interested in the response code, use the {@link #complete()} method which will automatically
1875    *       consume the response so that you don't need to call {@link InputStream#close()} on the response body.
1876    * </ul>
1877    *
1878    * @return The response object.
1879    * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt.
1880    */
1881   @SuppressWarnings("null")
1882   public RestResponse run() throws RestCallException {
1883      if (nn(response))
1884         throw new RestCallException(response, null, "run() already called.");
1885
1886      try {
1887
1888         queryData.stream().map(SimpleQuery::new).filter(SimplePart::isValid).forEach(x -> uriBuilder.addParameter(x.name, x.value));
1889
1890         pathData.stream().map(SimplePath::new).forEach(x -> {
1891            var path = uriBuilder.getPath();
1892            var name = x.name;
1893            var value = x.value;
1894            var var = "{" + name + "}";
1895            if (path.indexOf(var) == -1 && ! name.equals("/*"))
1896               throw new IllegalStateException("Path variable {" + name + "} was not found in path.");
1897            if (name.equals("/*"))
1898               path = path.replaceAll("\\/\\*$", "/" + value);
1899            else
1900               path = path.replace(var, String.valueOf(value));
1901            uriBuilder.setPath(path);
1902         });
1903
1904         HttpEntityEnclosingRequestBase request2 = request instanceof HttpEntityEnclosingRequestBase request3 ? request3 : null;
1905         request.setURI(uriBuilder.build());
1906
1907         // Pick the serializer if it hasn't been overridden.
1908         var hl = headerData;
1909         var h = hl.getLast("Content-Type");
1910         var contentType = h.isPresent() ? h.get().getValue() : null;
1911         var serializer = this.serializer;
1912         if (serializer == null)
1913            serializer = client.getMatchingSerializer(contentType);
1914         if (contentType == null && nn(serializer))
1915            contentType = serializer.getPrimaryMediaType().toString();
1916
1917         // Pick the parser if it hasn't been overridden.
1918         h = hl.getLast("Accept");
1919         var accept = h.isPresent() ? h.get().getValue() : null;
1920         var parser = this.parser;
1921         if (parser == null)
1922            parser = client.getMatchingParser(accept);
1923         if (accept == null && nn(parser))
1924            hl.set(Accept.of(parser.getPrimaryMediaType()));
1925
1926         headerData.stream().map(SimpleHeader::new).filter(SimplePart::isValid).forEach(x -> request.addHeader(x));
1927
1928         if (request2 == null && content != NO_BODY)
1929            throw new RestCallException(null, null, "Method does not support content entity.  Method={0}, URI={1}", getMethod(), getURI());
1930
1931         if (nn(request2)) {
1932
1933            var input2 = (Object)null;
1934            if (content != NO_BODY) {
1935               input2 = content;
1936            } else {
1937               input2 = new UrlEncodedFormEntity(formData.stream().map(SimpleFormData::new).filter(SimplePart::isValid).collect(toList()));
1938            }
1939
1940            if (input2 instanceof Supplier<?> s)
1941               input2 = s.get();
1942
1943            var entity = (HttpEntity)null;
1944            if (input2 instanceof PartList input22)
1945               entity = new UrlEncodedFormEntity(input22.stream().map(SimpleFormData::new).filter(SimplePart::isValid).collect(toList()));
1946            else if (input2 instanceof HttpResource input23) {
1947               input23.getHeaders().forEach(x -> request.addHeader(x));
1948               entity = (HttpEntity)input2;
1949            } else if (input2 instanceof HttpEntity input3) {
1950               if (input3 instanceof SerializedEntity input32) {
1951                  entity = input32.copyWith(serializer, contentSchema);
1952               } else {
1953                  entity = input3;
1954               }
1955            } else if (input2 instanceof Reader input24)
1956               entity = readerEntity(input24, getRequestContentType(TEXT_PLAIN));
1957            else if (input2 instanceof InputStream input25)
1958               entity = streamEntity(input25, -1, getRequestContentType(ContentType.APPLICATION_OCTET_STREAM));
1959            else if (nn(serializer))
1960               entity = serializedEntity(input2, serializer, contentSchema).setContentType(contentType);
1961            else {
1962               if (client.hasSerializers()) {
1963                  if (contentType == null)
1964                     throw new RestCallException(null, null,
1965                        "Content-Type not specified on request.  Cannot match correct serializer.  Use contentType(String) or mediaType(String) to specify transport language.");
1966                  throw new RestCallException(null, null, "No matching serializer for media type ''{0}''", contentType);
1967               }
1968               entity = stringEntity(input2 == null ? "" : BeanContext.DEFAULT.getClassMetaForObject(input2).toString(input2), getRequestContentType(TEXT_PLAIN));
1969            }
1970
1971            request2.setEntity(entity);
1972         }
1973
1974         try {
1975            response = client.createResponse(this, client.run(target, request, context), parser);
1976         } catch (Exception e) {
1977            throw e;
1978         }
1979
1980         if (isDebug() || client.logRequests == DetailLevel.FULL)
1981            response.cacheContent();
1982
1983         for (var rci : interceptors)
1984            rci.onConnect(this, response);
1985         client.onCallConnect(this, response);
1986
1987         var method = getMethod();
1988         var sc = response.getStatusCode();
1989
1990         var thrown = response.getHeader("Thrown").asHeader(Thrown.class);
1991         if (thrown.isPresent() && nn(rethrow)) {
1992            var thrownPart = thrown.asParts().get().get(0);
1993            var className = thrownPart.getClassName();
1994            var message = thrownPart.getMessage();
1995            for (var t : rethrow) {
1996               if (t.getName().equals(className)) {
1997                  var c = (ConstructorInfo)null;
1998                  var ci = ClassInfo.of(t);
1999                  c = ci.getPublicConstructor(x -> x.hasParameterTypes(HttpResponse.class)).orElse(null);
2000                  if (nn(c))
2001                     throw c.<Throwable>newInstance(response);
2002                  c = ci.getPublicConstructor(x -> x.hasParameterTypes(String.class)).orElse(null);
2003                  if (nn(c))
2004                     throw c.<Throwable>newInstance(nn(message) ? message : response.getContent().asString());
2005                  c = ci.getPublicConstructor(x -> x.hasParameterTypes(String.class, Throwable.class)).orElse(null);
2006                  if (nn(c))
2007                     throw c.<Throwable>newInstance(nn(message) ? message : response.getContent().asString(), null);
2008                  c = ci.getPublicConstructor(cons -> cons.getParameterCount() == 0).orElse(null);
2009                  if (nn(c))
2010                     throw c.<Throwable>newInstance();
2011               }
2012            }
2013         }
2014
2015         if (errorCodes.test(sc) && ! ignoreErrors) {
2016            throw new RestCallException(response, null, "HTTP method ''{0}'' call to ''{1}'' caused response code ''{2}, {3}''.\nResponse: \n{4}", method, getURI(), sc, response.getReasonPhrase(),
2017               response.getContent().asAbbreviatedString(1000));
2018         }
2019
2020      } catch (RuntimeException | RestCallException e) {
2021         if (nn(response))
2022            response.close();
2023         throw e;
2024      } catch (Throwable e) {
2025         if (nn(response))
2026            response.close();
2027         throw new RestCallException(response, e, "Call failed.");
2028      }
2029
2030      return this.response;
2031   }
2032
2033   /**
2034    * Same as {@link #run()} but allows you to run the call asynchronously.
2035    *
2036    * <h5 class='section'>Example:</h5>
2037    * <p class='bjava'>
2038    *    Future&lt;RestResponse&gt; <jv>future</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).runFuture();
2039    *
2040    *    <jc>// Do some other stuff</jc>
2041    *
2042    *    <jk>try</jk> {
2043    *       String <jv>body</jv> = <jv>future</jv>.get().getContent().asString();
2044    *       <jc>// Succeeded!</jc>
2045    *    } <jk>catch</jk> (RestCallException <jv>e</jv>) {
2046    *       <jc>// Failed!</jc>
2047    *    }
2048    * </p>
2049    *
2050    * <h5 class='section'>Notes:</h5><ul>
2051    *    <li class='note'>Use the {@link RestClient.Builder#executorService(ExecutorService, boolean)} method to customize the
2052    *       executor service used for creating {@link Future Futures}.
2053    * </ul>
2054    *
2055    * @return The HTTP status code.
2056    * @throws RestCallException If the executor service was not defined.
2057    */
2058   public Future<RestResponse> runFuture() throws RestCallException {
2059      return client.getExecutorService().submit(this::run);
2060   }
2061
2062   /**
2063    * Specifies the serializer to use on the request body.
2064    *
2065    * <p>
2066    * Overrides the serializers specified on the {@link RestClient}.
2067    *
2068    * <p>
2069    *    The serializer can be configured using any of the serializer property setters (e.g. {@link RestClient.Builder#sortCollections()}) or
2070    *    bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
2071    *
2072    * <p>
2073    * If the <c>Content-Type</c> header is not set on the request, it will be set to the media type of this serializer.
2074    *
2075    * @param serializer The serializer used to serialize POJOs to the body of the HTTP request.
2076    *    <br>Can be <jk>null</jk> (will use default serializer matching Content-Type).
2077    * @return This object.
2078    */
2079   public RestRequest serializer(Class<? extends Serializer> serializer) {
2080      this.serializer = serializer == null ? null : client.getInstance(serializer);
2081      return this;
2082   }
2083
2084   /**
2085    * Specifies the serializer to use on the request body.
2086    *
2087    * <p>
2088    * Overrides the serializers specified on the {@link RestClient}.
2089    *
2090    * <p>
2091    *    The serializer is not modified by an of the serializer property setters (e.g. {@link RestClient.Builder#sortCollections()}) or
2092    *    bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
2093    *
2094    * <p>
2095    * If the <c>Content-Type</c> header is not set on the request, it will be set to the media type of this serializer.
2096    *
2097    * @param serializer The serializer used to serialize POJOs to the body of the HTTP request.
2098    *    <br>Can be <jk>null</jk> (will use default serializer matching Content-Type).
2099    * @return This object.
2100    */
2101   public RestRequest serializer(Serializer serializer) {
2102      this.serializer = serializer;
2103      return this;
2104   }
2105
2106   /**
2107    * Overwrites the first header with the same name.
2108    *
2109    * The new header will be appended to the end of the list, if no header with the given name can be found.
2110    *
2111    * @param header The header to set.
2112    *    <br>Can be <jk>null</jk> (ignored).
2113    */
2114   @Override /* Overridden from HttpMessage */
2115   public void setHeader(Header header) {
2116      headerData.set(header);
2117   }
2118
2119   /**
2120    * Overwrites the first header with the same name.
2121    *
2122    * The new header will be appended to the end of the list, if no header with the given name can be found.
2123    *
2124    * @param name The name of the header.
2125    *    <br>Cannot be <jk>null</jk> or empty (header will not be created).
2126    * @param value The value of the header.
2127    *    <br>Can be <jk>null</jk>.
2128    */
2129   @Override /* Overridden from HttpMessage */
2130   public void setHeader(String name, String value) {
2131      headerData.set(stringHeader(name, value));
2132   }
2133
2134   /**
2135    * Overwrites all the headers in the message.
2136    *
2137    * @param headers The array of headers to set.
2138    *    <br>Can be <jk>null</jk> (all headers will be cleared).
2139    *    <br>Can contain <jk>null</jk> values (ignored).
2140    */
2141   @Override /* Overridden from HttpMessage */
2142   public void setHeaders(Header[] headers) {
2143      headerData.set(headers);
2144   }
2145
2146   /**
2147    * Provides parameters to be used for the processing of this message.
2148    *
2149    * @param params The parameters.
2150    *    <br>Can be <jk>null</jk> (default parameters will be used).
2151    * @deprecated Use constructor parameters of configuration API provided by HttpClient.
2152    */
2153   @Override /* Overridden from HttpMessage */
2154   @Deprecated
2155   public void setParams(HttpParams params) {
2156      request.setParams(params);
2157   }
2158
2159   /**
2160    * Causes logging to be suppressed for the duration of this request.
2161    *
2162    * <p>
2163    * Overrides the {@link #debug()} setting on this request or client.
2164    *
2165    * @return This object.
2166    */
2167   public RestRequest suppressLogging() {
2168      this.suppressLogging = true;
2169      return this;
2170   }
2171
2172   /**
2173    * Specifies the target host for the request.
2174    *
2175    * @param target The target host for the request.
2176    *    Implementations may accept <jk>null</jk> if they can still determine a route, for example to a default
2177    *    target or by inspecting the request.
2178    * @return This object.
2179    */
2180   public RestRequest target(HttpHost target) {
2181      this.target = target;
2182      return this;
2183   }
2184
2185   /**
2186    * Convenience method for specifying UON as the marshalling transmission media type for this request only.
2187    *
2188    * <p>
2189    * UON is Url-Encoding Object notation that is equivalent to JSON but suitable for transmission as URL-encoded
2190    * query and form post values.
2191    *
2192    * <p>
2193    *    {@link UonSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
2194    *    <ul>
2195    *       <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClient.Builder#sortCollections()}) or
2196    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
2197    *    </ul>
2198    * <p>
2199    *    {@link UonParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
2200    *    <ul>
2201    *       <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClient.Builder#strict()}) or
2202    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
2203    *    </ul>
2204    * <p>
2205    *    <c>Accept</c> request header will be set to <js>"text/uon"</js> unless overridden
2206    *       by {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(String)}.
2207    * <p>
2208    *    <c>Content-Type</c> request header will be set to <js>"text/uon"</js> unless overridden
2209    *       by {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(String)}.
2210    * <p>
2211    *    Identical to calling <c>serializer(UonSerializer.<jk>class</jk>).parser(UonParser.<jk>class</jk>)</c>.
2212    *
2213    * @return This object.
2214    */
2215   public RestRequest uon() {
2216      return serializer(UonSerializer.class).parser(UonParser.class);
2217   }
2218
2219   /**
2220    * Sets the URI for this request.
2221    *
2222    * <p>
2223    * Can be any of the following types:
2224    * <ul>
2225    *    <li>{@link URI}
2226    *    <li>{@link URL}
2227    *    <li>{@link URIBuilder}
2228    *    <li>Anything else converted to a string using {@link Object#toString()}.
2229    * </ul>
2230    *
2231    * <p>
2232    * Relative URI strings will be interpreted as relative to the root URI defined on the client.
2233    *
2234    * @param uri
2235    *    The URI of the remote REST resource.
2236    *    <br>This overrides the URI passed in from the client.
2237    *    <br>Can be any of the following types:
2238    *    <ul>
2239    *       <li>{@link URIBuilder}
2240    *       <li>{@link URI}
2241    *       <li>{@link URL}
2242    *       <li>{@link String}
2243    *       <li>{@link Object} - Converted to <c>String</c> using <c>toString()</c>
2244    *    </ul>
2245    *    <br>Cannot be <jk>null</jk>.
2246    * @return This object.
2247    * @throws RestCallException Invalid URI syntax detected.
2248    */
2249   public RestRequest uri(Object uri) throws RestCallException {
2250      var x = client.toUri(uri, null);
2251      if (nn(x.getScheme()))
2252         uriBuilder.setScheme(x.getScheme());
2253      if (nn(x.getHost()))
2254         uriBuilder.setHost(x.getHost());
2255      if (x.getPort() != -1)
2256         uriBuilder.setPort(x.getPort());
2257      if (nn(x.getUserInfo()))
2258         uriBuilder.setUserInfo(x.getUserInfo());
2259      if (nn(x.getFragment()))
2260         uriBuilder.setFragment(x.getFragment());
2261      if (nn(x.getQuery()))
2262         uriBuilder.setCustomQuery(x.getQuery());
2263      uriBuilder.setPath(x.getPath());
2264      return this;
2265   }
2266
2267   /**
2268    * Sets the URI fragment.
2269    *
2270    * @param fragment The URI fragment.  The value is expected to be unescaped and may contain non ASCII characters.
2271    *    <br>Can be <jk>null</jk> (fragment will be cleared).
2272    * @return This object.
2273    */
2274   public RestRequest uriFragment(String fragment) {
2275      uriBuilder.setFragment(fragment);
2276      return this;
2277   }
2278
2279   /**
2280    * Sets the URI host.
2281    *
2282    * @param host The new URI host.
2283    *    <br>Can be <jk>null</jk> (host will be cleared).
2284    * @return This object.
2285    */
2286   public RestRequest uriHost(String host) {
2287      uriBuilder.setHost(host);
2288      return this;
2289   }
2290
2291   /**
2292    * Sets the URI port.
2293    *
2294    * @param port The new URI port.
2295    * @return This object.
2296    */
2297   public RestRequest uriPort(int port) {
2298      uriBuilder.setPort(port);
2299      return this;
2300   }
2301
2302   /**
2303    * Sets the URI scheme.
2304    *
2305    * @param scheme The new URI scheme.
2306    *    <br>Can be <jk>null</jk> (scheme will be cleared).
2307    * @return This object.
2308    */
2309   public RestRequest uriScheme(String scheme) {
2310      uriBuilder.setScheme(scheme);
2311      return this;
2312   }
2313
2314   /**
2315    * Sets the URI user info.
2316    *
2317    * @param userInfo The new URI user info.
2318    *    <br>Can be <jk>null</jk> (user info will be cleared).
2319    * @return This object.
2320    */
2321   public RestRequest uriUserInfo(String userInfo) {
2322      uriBuilder.setUserInfo(userInfo);
2323      return this;
2324   }
2325
2326   /**
2327    * Sets the URI user info.
2328    *
2329    * @param username The new URI username.
2330    *    <br>Can be <jk>null</jk>.
2331    * @param password The new URI password.
2332    *    <br>Can be <jk>null</jk>.
2333    * @return This object.
2334    */
2335   public RestRequest uriUserInfo(String username, String password) {
2336      uriBuilder.setUserInfo(username, password);
2337      return this;
2338   }
2339
2340   /**
2341    * Convenience method for specifying URL-Encoding as the marshalling transmission media type for this request only.
2342    *
2343    * <p>
2344    *    {@link UrlEncodingSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
2345    *    <ul>
2346    *       <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClient.Builder#sortCollections()}) or
2347    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
2348    *       <li>This serializer is NOT used when using the {@link RestRequest#formData(String, Object)} (and related) methods for constructing
2349    *          the request body.  Instead, the part serializer specified via {@link RestClient.Builder#partSerializer(Class)} is used.
2350    *    </ul>
2351    * <p>
2352    *    {@link UrlEncodingParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
2353    *    <ul>
2354    *       <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClient.Builder#strict()}) or
2355    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
2356    *    </ul>
2357    * <p>
2358    *    <c>Accept</c> request header will be set to <js>"application/x-www-form-urlencoded"</js> unless overridden
2359    *       by {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(String)}.
2360    * <p>
2361    *    <c>Content-Type</c> request header will be set to <js>"application/x-www-form-urlencoded"</js> unless overridden
2362    *       by {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(String)}.
2363    * <p>
2364    *    Identical to calling <c>serializer(UrlEncodingSerializer.<jk>class</jk>).parser(UrlEncodingParser.<jk>class</jk>)</c>.
2365    *
2366    * @return This object.
2367    */
2368   public RestRequest urlEnc() {
2369      return serializer(UrlEncodingSerializer.class).parser(UrlEncodingParser.class);
2370   }
2371
2372   /**
2373    * Convenience method for specifying XML as the marshalling transmission media type for this request only.
2374    *
2375    * <p>
2376    * {@link XmlSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
2377    *    <ul>
2378    *       <li>The serializer can be configured using any of the serializer property setters (e.g. {@link RestClient.Builder#sortCollections()}) or
2379    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
2380    *    </ul>
2381    * <p>
2382    *    {@link XmlParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
2383    *    <ul>
2384    *       <li>The parser can be configured using any of the parser property setters (e.g. {@link RestClient.Builder#strict()}) or
2385    *          bean context property setters (e.g. {@link RestClient.Builder#swaps(Class...)}) defined on this builder class.
2386    *    </ul>
2387    * <p>
2388    *    <c>Accept</c> request header will be set to <js>"text/xml"</js> unless overridden
2389    *       by {@link RestRequest#header(String,Object)} or {@link RestRequest#accept(String)}.
2390    * <p>
2391    *    <c>Content-Type</c> request header will be set to <js>"text/xml"</js> unless overridden
2392    *       by {@link RestRequest#header(String,Object)} or {@link RestRequest#contentType(String)}.
2393    * <p>
2394    *    Identical to calling <c>serializer(XmlSerializer.<jk>class</jk>).parser(XmlParser.<jk>class</jk>)</c>.
2395    *
2396    * @return This object.
2397    */
2398   public RestRequest xml() {
2399      return serializer(XmlSerializer.class).parser(XmlParser.class);
2400   }
2401
2402   private Header createHeader(String name, Object value) {
2403      return createHeader(name, value, null, null, null);
2404   }
2405
2406   private NameValuePair createPart(HttpPartType type, String name, Object value) {
2407      return createPart(name, value, type, null, null, null);
2408   }
2409
2410   private HttpPartSerializerSession getPartSerializerSession(HttpPartSerializer serializer) {
2411      if (serializer == null)
2412         serializer = client.getPartSerializer();
2413      var s = partSerializerSessions.get(serializer);
2414      if (s == null) {
2415         s = serializer.getPartSession();
2416         partSerializerSessions.put(serializer, s);
2417      }
2418      return s;
2419   }
2420
2421   private ContentType getRequestContentType(ContentType def) {
2422      var h = request.getFirstHeader("Content-Type");
2423      if (nn(h)) {
2424         var s = h.getValue();
2425         if (ne(s))
2426            return ContentType.of(s);
2427      }
2428      return def;
2429   }
2430
2431   /**
2432    * Creates a new header.
2433    *
2434    * @param name The header name.
2435    * @param value The header value.
2436    * @param serializer The part serializer to use, or <jk>null</jk> to use the part serializer defined on the client.
2437    * @param schema Optional HTTP part schema to provide to the part serializer.
2438    * @param skipIfEmpty If <jk>true</jk>, empty string values will be ignored on the request.
2439    * @return A new header.
2440    */
2441   protected Header createHeader(String name, Object value, HttpPartSerializer serializer, HttpPartSchema schema, Boolean skipIfEmpty) {
2442      if (e(name))
2443         return null;
2444      if (skipIfEmpty == null)
2445         skipIfEmpty = client.isSkipEmptyHeaderData();
2446      if (serializer == null)
2447         serializer = client.getPartSerializer();
2448      return new SerializedHeader(name, value, getPartSerializerSession(serializer), schema, skipIfEmpty);
2449   }
2450
2451   /**
2452    * Constructs the {@link HttpRequestBase} object that ends up being passed to the client execute method.
2453    *
2454    * <p>
2455    * Subclasses can override this method to create their own request base objects.
2456    *
2457    * @param method The HTTP method.
2458    * @param uri The HTTP URI.
2459    * @param hasBody Whether the HTTP request has a body.
2460    * @return A new {@link HttpRequestBase} object.
2461    */
2462   protected HttpRequestBase createInnerRequest(String method, URI uri, boolean hasBody) {
2463      var req = hasBody ? new BasicHttpEntityRequestBase(this, method) : new BasicHttpRequestBase(this, method);
2464      req.setURI(uri);
2465      return req;
2466   }
2467
2468   /**
2469    * Creates a new query/form-data/path part.
2470    *
2471    * @param name The part name.
2472    * @param value The part value.
2473    * @param type The HTTP part type.
2474    * @param serializer The part serializer to use, or <jk>null</jk> to use the part serializer defined on the client.
2475    * @param schema Optional HTTP part schema to provide to the part serializer.
2476    * @param skipIfEmpty If <jk>true</jk>, empty string values will be ignored on the request.
2477    * @return A new part.
2478    */
2479   protected NameValuePair createPart(String name, Object value, HttpPartType type, HttpPartSerializer serializer, HttpPartSchema schema, Boolean skipIfEmpty) {
2480      if (e(name))
2481         return null;
2482      if (skipIfEmpty == null) {
2483         if (type == QUERY)
2484            skipIfEmpty = client.isSkipEmptyQueryData();
2485         else if (type == FORMDATA)
2486            skipIfEmpty = client.isSkipEmptyFormData();
2487         else
2488            skipIfEmpty = false;
2489      }
2490      if (serializer == null)
2491         serializer = client.getPartSerializer();
2492      return new SerializedPart(name, value, type, getPartSerializerSession(serializer), schema, skipIfEmpty);
2493   }
2494
2495   @Override /* Overridden from BeanSession */
2496   protected FluentMap<String,Object> properties() {
2497      return super.properties()
2498         .a("client", client.properties())
2499         .a("ignoreErrors", ignoreErrors)
2500         .a("interceptors", interceptors)
2501         .a("requestBodySchema", contentSchema)
2502         .a("response", response)
2503         .a("serializer", serializer);
2504   }
2505
2506   RestRequest formDataArg(String name, Object value, HttpPartSchema schema, HttpPartSerializer serializer, boolean skipIfEmpty) {
2507      var isMulti = e(name) || "*".equals(name) || value instanceof PartList || isNameValuePairArray(value);
2508
2509      if (! isMulti) {
2510         if (! (skipIfEmpty && e(s(value))))
2511            return formData(createPart(name, value, FORMDATA, serializer, schema, skipIfEmpty));
2512         return this;
2513      }
2514
2515      List<NameValuePair> l = list();
2516
2517      if (HttpParts.canCast(value)) {
2518         l.add(HttpParts.cast(value));
2519      } else if (value instanceof PartList value2) {
2520         value2.forEach(x -> l.add(x));
2521      } else if (value instanceof Collection<?> value3) {
2522         value3.forEach(x -> l.add(HttpParts.cast(x)));
2523      } else if (isArray(value)) {
2524         for (var i = 0; i < Array.getLength(value); i++)
2525            l.add(HttpParts.cast(Array.get(value, i)));
2526      } else if (value instanceof Map value4) {
2527         toMap(value4).forEach((k, v) -> l.add(createPart(s(k), v, FORMDATA, serializer, schema, skipIfEmpty)));
2528      } else if (isBean(value)) {
2529         toBeanMap(value).forEach((k, v) -> l.add(createPart(k, v, FORMDATA, serializer, schema, skipIfEmpty)));
2530      } else if (nn(value)) {
2531         formDataCustom(value);
2532         return this;
2533      }
2534
2535      if (skipIfEmpty)
2536         l.removeIf(x -> e(x.getValue()));
2537
2538      formData.append(l);
2539
2540      return this;
2541   }
2542
2543   HttpPartSerializerSession getPartSerializerSession() {
2544      if (partSerializerSession == null)
2545         partSerializerSession = getPartSerializerSession(null);
2546      return partSerializerSession;
2547   }
2548
2549   RestRequest headerArg(String name, Object value, HttpPartSchema schema, HttpPartSerializer serializer, boolean skipIfEmpty) {
2550      var isMulti = e(name) || "*".equals(name) || value instanceof HeaderList || isHeaderArray(value);
2551
2552      if (! isMulti) {
2553         if (! (skipIfEmpty && e(s(value))))
2554            return header(createHeader(name, value, serializer, schema, skipIfEmpty));
2555         return this;
2556      }
2557
2558      List<Header> l = list();
2559
2560      if (HttpHeaders.canCast(value)) {
2561         l.add(HttpHeaders.cast(value));
2562      } else if (value instanceof HeaderList value2) {
2563         value2.forEach(x -> l.add(x));
2564      } else if (value instanceof Collection<?> value3) {
2565         value3.forEach(x -> l.add(HttpHeaders.cast(x)));
2566      } else if (isArray(value)) {
2567         for (var i = 0; i < Array.getLength(value); i++)
2568            l.add(HttpHeaders.cast(Array.get(value, i)));
2569      } else if (value instanceof Map value2) {
2570         toMap(value2).forEach((k, v) -> l.add(createHeader(s(k), v, serializer, schema, skipIfEmpty)));
2571      } else if (isBean(value)) {
2572         toBeanMap(value).forEach((k, v) -> l.add(createHeader(k, v, serializer, schema, skipIfEmpty)));
2573      } else if (nn(value)) {
2574         throw rex("Invalid value type for header arg ''{0}'': {1}", name, cn(value));
2575      }
2576
2577      if (skipIfEmpty)
2578         l.removeIf(x -> e(x.getValue()));
2579
2580      headerData.append(l);
2581
2582      return this;
2583   }
2584
2585   boolean isLoggingSuppressed() { return suppressLogging; }
2586
2587   RestRequest pathArg(String name, Object value, HttpPartSchema schema, HttpPartSerializer serializer) {
2588      var isMulti = e(name) || "*".equals(name) || value instanceof PartList || isNameValuePairArray(value);
2589
2590      if (! isMulti)
2591         return pathData(createPart(name, value, PATH, serializer, schema, false));
2592
2593      List<NameValuePair> l = list();
2594
2595      if (HttpParts.canCast(value)) {
2596         l.add(HttpParts.cast(value));
2597      } else if (value instanceof PartList value2) {
2598         value2.forEach(x -> l.add(x));
2599      } else if (value instanceof Collection<?> value3) {
2600         value3.forEach(x -> l.add(HttpParts.cast(x)));
2601      } else if (isArray(value)) {
2602         for (var i = 0; i < Array.getLength(value); i++)
2603            l.add(HttpParts.cast(Array.get(value, i)));
2604      } else if (value instanceof Map value4) {
2605         toMap(value4).forEach((k, v) -> l.add(createPart(s(k), v, PATH, serializer, schema, false)));
2606      } else if (isBean(value)) {
2607         toBeanMap(value).forEach((k, v) -> l.add(createPart(k, v, PATH, serializer, schema, false)));
2608      } else if (nn(value)) {
2609         throw rex("Invalid value type for path arg ''{0}'': {1}", name, cn(value));
2610      }
2611
2612      pathData.append(l);
2613
2614      return this;
2615   }
2616
2617   RestRequest queryArg(String name, Object value, HttpPartSchema schema, HttpPartSerializer serializer, boolean skipIfEmpty) {
2618      var isMulti = e(name) || "*".equals(name) || value instanceof PartList || isNameValuePairArray(value);
2619
2620      if (! isMulti) {
2621         if (! (skipIfEmpty && e(s(value))))
2622            return queryData(createPart(name, value, QUERY, serializer, schema, skipIfEmpty));
2623         return this;
2624      }
2625
2626      List<NameValuePair> l = list();
2627
2628      if (HttpParts.canCast(value)) {
2629         l.add(HttpParts.cast(value));
2630      } else if (value instanceof PartList value2) {
2631         value2.forEach(x -> l.add(x));
2632      } else if (value instanceof Collection<?> value3) {
2633         value3.forEach(x -> l.add(HttpParts.cast(x)));
2634      } else if (isArray(value)) {
2635         for (var i = 0; i < Array.getLength(value); i++)
2636            l.add(HttpParts.cast(Array.get(value, i)));
2637      } else if (value instanceof Map value4) {
2638         toMap(value4).forEach((k, v) -> l.add(createPart(s(k), v, QUERY, serializer, schema, skipIfEmpty)));
2639      } else if (isBean(value)) {
2640         toBeanMap(value).forEach((k, v) -> l.add(createPart(k, v, QUERY, serializer, schema, skipIfEmpty)));
2641      } else if (nn(value)) {
2642         queryCustom(value);
2643         return this;
2644      }
2645
2646      if (skipIfEmpty)
2647         l.removeIf(x -> e(x.getValue()));
2648
2649      queryData.append(l);
2650
2651      return this;
2652   }
2653}