![JAR search and dependency download from the Maven repository](/logo.png)
org.apache.juneau.rest.client.RestClient Maven / Gradle / Ivy
// ***************************************************************************************************************************
// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
// * with the License. You may obtain a copy of the License at *
// * *
// * http://www.apache.org/licenses/LICENSE-2.0 *
// * *
// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
// * specific language governing permissions and limitations under the License. *
// ***************************************************************************************************************************
package org.apache.juneau.rest.client;
import static org.apache.juneau.httppart.HttpPartType.*;
import static org.apache.juneau.http.HttpMethod.*;
import static org.apache.juneau.http.HttpHeaders.*;
import static org.apache.juneau.http.HttpParts.*;
import static org.apache.juneau.collections.JsonMap.*;
import static org.apache.juneau.common.internal.ArgUtils.*;
import static org.apache.juneau.common.internal.StringUtils.*;
import static org.apache.juneau.common.internal.ThrowableUtils.*;
import static org.apache.juneau.http.HttpEntities.*;
import static org.apache.juneau.rest.client.RestOperation.*;
import static java.util.logging.Level.*;
import static org.apache.juneau.internal.CollectionUtils.*;
import static org.apache.juneau.internal.StateMachineState.*;
import static java.lang.Character.*;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.lang.reflect.Proxy;
import java.net.*;
import java.nio.charset.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.*;
import java.util.logging.*;
import java.util.regex.*;
import javax.net.ssl.*;
import org.apache.http.*;
import org.apache.http.Header;
import org.apache.http.auth.*;
import org.apache.http.client.*;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.*;
import org.apache.http.client.entity.*;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.*;
import org.apache.http.config.*;
import org.apache.http.conn.*;
import org.apache.http.conn.routing.*;
import org.apache.http.conn.socket.*;
import org.apache.http.conn.util.*;
import org.apache.http.cookie.*;
import org.apache.http.impl.client.*;
import org.apache.http.impl.conn.*;
import org.apache.http.params.*;
import org.apache.http.protocol.*;
import org.apache.juneau.*;
import org.apache.juneau.annotation.*;
import org.apache.juneau.collections.*;
import org.apache.juneau.cp.*;
import org.apache.juneau.html.*;
import org.apache.juneau.http.remote.RemoteReturn;
import org.apache.juneau.http.resource.*;
import org.apache.juneau.http.entity.*;
import org.apache.juneau.http.header.*;
import org.apache.juneau.http.part.*;
import org.apache.juneau.http.remote.*;
import org.apache.juneau.httppart.*;
import org.apache.juneau.httppart.bean.*;
import org.apache.juneau.internal.*;
import org.apache.juneau.json.*;
import org.apache.juneau.marshaller.*;
import org.apache.juneau.msgpack.*;
import org.apache.juneau.oapi.*;
import org.apache.juneau.objecttools.*;
import org.apache.juneau.parser.*;
import org.apache.juneau.parser.ParseException;
import org.apache.juneau.plaintext.*;
import org.apache.juneau.reflect.*;
import org.apache.juneau.rest.client.assertion.*;
import org.apache.juneau.rest.client.remote.*;
import org.apache.juneau.serializer.*;
import org.apache.juneau.uon.*;
import org.apache.juneau.urlencoding.*;
import org.apache.juneau.utils.*;
import org.apache.juneau.xml.*;
/**
* Utility class for interfacing with remote REST interfaces.
*
*
* Built upon the feature-rich Apache HttpClient library, the Juneau RestClient API adds support for fluent-style
* REST calls and the ability to perform marshalling of POJOs to and from HTTP parts.
*
*
Example:
*
* // Create a basic REST client with JSON support and download a bean.
* MyBean bean = RestClient.create ()
* .json5()
* .build()
* .get(URI )
* .run()
* .assertStatus().asCode().is(200)
* .assertHeader("Content-Type" ).matchesSimple("application/json*" )
* .getContent().as(MyBean.class );
*
*
*
* Breaking apart the fluent call, we can see the classes being used:
*
* RestClient.Builder builder = RestClient.create ().json5();
* RestClient client = builder .build();
* RestRequest req = client .get(URI );
* RestResponse res = req .run();
* RestResponseStatusLineAssertion statusLineAssertion = res .assertStatus();
* FluentIntegerAssertion<RestResponse> codeAssertion = statusLineAssertion .asCode();
* res = codeAssertion .is(200);
* FluentStringAssertion<RestResponse> headerAssertion = res .assertHeader("Content-Type" );
* res = headerAssertion .matchesSimple("application/json*" );
* RestResponseBody content = res .getContent();
* MyBean bean = content .as(MyBean.class );
*
*
*
* It additionally provides support for creating remote proxy interfaces using REST as the transport medium.
*
*
Example:
*
* // Define a Remote proxy for interacting with a REST interface.
* @Remote (path="/petstore" )
* public interface PetStore {
*
* @RemotePost ("/pets" )
* Pet addPet(
* @Content CreatePet pet ,
* @Header ("E-Tag" ) UUID etag ,
* @Query ("debug" ) boolean debug
* );
* }
*
* // Use a RestClient with default JSON 5 support.
* RestClient client = RestClient.create ().json5().build();
*
* PetStore store = client .getRemote(PetStore.class , "http://localhost:10000" );
* CreatePet createPet = new CreatePet("Fluffy" , 9.99);
* Pet pet = store .addPet(createPet , UUID.randomUUID (), true );
*
*
*
* The classes are closely tied to Apache HttpClient, yet provide lots of additional functionality:
*
* - {@link RestClient}
extends {@link HttpClient}, creates {@link RestRequest} objects.
* - {@link RestRequest}
extends {@link HttpUriRequest}, creates {@link RestResponse} objects.
* - {@link RestResponse} creates {@link ResponseContent} and {@link ResponseHeader} objects.
*
- {@link ResponseContent}
extends {@link HttpEntity}
* - {@link ResponseHeader}
extends {@link Header}
*
*
*
*
* Instances of this class are built using the {@link Builder} class which can be constructed using
* the {@link #create() RestClient.create()} method as shown above.
*
*
* Clients are typically created with a root URI so that relative URIs can be used when making requests.
* This is done using the {@link Builder#rootUrl(Object)} method.
*
*
Example:
*
* // Create a client where all URIs are relative to localhost.
* RestClient client = RestClient.create ().json().rootUrl("http://localhost:5000" ).build();
*
* // Use relative paths.
* String body = client .get("/subpath" ).run().getContent().asString();
*
*
*
* The {@link RestClient} class creates {@link RestRequest} objects using the following methods:
*
*
* - {@link RestClient}
*
* - {@link RestClient#get(Object) get(uri)} / {@link RestClient#get() get()}
*
- {@link RestClient#put(Object,Object) put(uri,body)} / {@link RestClient#put(Object) put(uri)}
*
- {@link RestClient#post(Object) post(uri,body)} / {@link RestClient#post(Object) post(uri)}
*
- {@link RestClient#patch(Object,Object) patch(uri,body)} / {@link RestClient#patch(Object) patch(uri)}
*
- {@link RestClient#delete(Object) delete(uri)}
*
- {@link RestClient#head(Object) head(uri)}
*
- {@link RestClient#options(Object) options(uri)}
*
- {@link RestClient#formPost(Object,Object) formPost(uri,body)} / {@link RestClient#formPost(Object) formPost(uri)}
*
- {@link RestClient#formPostPairs(Object,String...) formPostPairs(uri,parameters...)}
*
- {@link RestClient#request(String,Object,Object) request(method,uri,body)}
*
*
*
*
* The {@link RestRequest} class creates {@link RestResponse} objects using the following methods:
*
*
* - {@link RestRequest}
*
* - {@link RestRequest#run() run()}
*
- {@link RestRequest#complete() complete()}
*
*
*
*
* The distinction between the two methods is that {@link RestRequest#complete() complete()} automatically consumes the response body and
* {@link RestRequest#run() run()} does not. Note that you must consume response bodies in order for HTTP connections to be freed up
* for reuse! The {@link InputStream InputStreams} returned by the {@link ResponseContent} object are auto-closing once
* they are exhausted, so it is often not necessary to explicitly close them.
*
*
* The following examples show the distinction between the two calls:
*
*
* // Consuming the response, so use run().
* String body = client .get(URI ).run().getContent().asString();
*
* // Only interested in response status code, so use complete().
* int status = client .get(URI ).complete().getStatusCode();
*
*
*
* POJO Marshalling
*
*
* By default, JSON support is provided for HTTP request and response bodies.
* Other languages can be specified using any of the following builder methods:
*
* - {@link Builder}
*
* - {@link Builder#json() json()}
*
- {@link Builder#json5() json5()}
*
- {@link Builder#xml() xml()}
*
- {@link Builder#html() html()}
*
- {@link Builder#plainText() plainText()}
*
- {@link Builder#msgPack() msgPack()}
*
- {@link Builder#uon() uon()}
*
- {@link Builder#urlEnc() urlEnc()}
*
- {@link Builder#openApi() openApi()}
*
*
*
* Example:
*
* // Create a basic REST client with JSON 5 support.
* // Typically easier to use when performing unit tests.
* RestClient client = RestClient.create ().json5().build();
*
*
*
* Clients can also support multiple languages:
*
*
Example:
*
* // Create a REST client with support for multiple languages.
* RestClient client1 = RestClient.create ().json().xml().openApi().build();
*
* // Create a REST client with support for all supported languages.
* RestClient client2 = RestClient.create ().universal().build();
*
*
*
* When using clients with multiple language support, you must specify the Content-Type header on requests
* with bodies to specify which serializer should be selected.
*
*
* // Create a REST client with support for multiple languages.
* RestClient client = RestClient.create ().universal().build();
*
* client
* .post(URI , myBean )
* .contentType("application/json" )
* .complete()
* .assertStatus().is(200);
*
*
*
* Languages can also be specified per-request.
*
*
* // Create a REST client with no default languages supported.
* RestClient client = RestClient.create ().build();
*
* // Use JSON for this request.
* client
* .post(URI , myBean )
* .json()
* .complete()
* .assertStatus().is(200);
*
*
*
*
* The {@link Builder} class provides convenience methods for setting common serializer and parser
* settings.
*
*
Example:
*
* // Create a basic REST client with JSON support.
* // Use single-quotes and whitespace.
* RestClient client = RestClient.create ().json().sq().ws().build();
*
*
*
* Other methods are also provided for specifying the serializers and parsers used for lower-level marshalling support:
*
* - {@link Builder}
*
* - {@link Builder#serializer(Serializer) serializer(Serializer)}
*
- {@link Builder#parser(Parser) parser(Parser)}
*
- {@link Builder#marshaller(Marshaller) marshaller(Marshaller)}
*
*
*
*
* HTTP parts (headers, query parameters, form data...) are serialized and parsed using the {@link HttpPartSerializer}
* and {@link HttpPartParser} APIs. By default, clients are configured to use {@link OpenApiSerializer} and
* {@link OpenApiParser}. These can be overridden using the following methods:
*
* - {@link Builder}
*
* - {@link Builder#partSerializer(Class) partSerializer(Class<? extends HttpPartSerializer>)}
*
- {@link Builder#partParser(Class) partParser(Class<? extends HttpPartParser>)}
*
*
*
*
* Request Headers
*
* Per-client or per-request headers can be specified using the following methods:
*
* - {@link Builder}
*
* - {@link Builder#headers() headerData()}
*
- {@link Builder#header(String,String) header(String,Object)}
*
- {@link Builder#header(String,Supplier) header(String,Supplier<?>)}
*
- {@link Builder#headers(Header...) headers(Header...)}
*
- {@link Builder#headersDefault(Header...) defaultHeaders(Header...)}
*
* - {@link RestRequest}
*
* - {@link RestRequest#header(String,Object) header(String,Object)}
*
- {@link RestRequest#headers(Header...) headers(Header...)}
*
- {@link RestRequest#headersBean(Object) headersBean(Object)}
*
- {@link RestRequest#headerPairs(String...) headerPairs(String...)}
*
*
*
*
* The supplier methods are particularly useful for header values whose values may change over time (such as Authorization headers
* which may need to change every few minutes).
*
*
* Example:
*
* // Create a client that adds a dynamic Authorization header to every request.
* RestClient client = RestClient.create ().header("Authorization" , ()->getMyAuthToken()).build();
*
*
*
* The {@link HttpPartSchema} API allows you to define OpenAPI schemas to POJO data structures on both requests
* and responses.
*
*
Example:
*
* // Create a client that adds a header "Foo: bar|baz" to every request.
* RestClient client = RestClient.create ()
* .header("Foo" , AList.of ("bar" ,"baz" ), T_ARRAY_PIPES )
* .build();
*
*
*
* The methods with {@link ListOperation} parameters allow you to control whether new headers get appended, prepended, or
* replace existing headers with the same name.
*
*
Notes:
* - Methods that pass in POJOs convert values to strings using the part serializers. Methods that pass in
Header or
* NameValuePair objects use the values returned by that bean directly.
*
*
*
* Request Query Parameters
*
* Per-client or per-request query parameters can be specified using the following methods:
*
* - {@link Builder}
*
* - {@link Builder#queryData() queryData()}
*
- {@link Builder#queryData(String,String) queryData(String,String)}
*
- {@link Builder#queryData(String,Supplier) queryData(String,Supplier<?>)}
*
- {@link Builder#queryData(NameValuePair...) queryData(NameValuePair...)}
*
- {@link Builder#queryDataDefault(NameValuePair...) defaultQueryData(NameValuePair...)}
*
* - {@link RestRequest}
*
* - {@link RestRequest#queryData(String,Object) queryData(String,Object)}
*
- {@link RestRequest#queryData(NameValuePair...) queryData(NameValuePair...)}
*
- {@link RestRequest#queryDataBean(Object) queryDataBean(Object)}
*
- {@link RestRequest#queryCustom(Object) queryCustom(Object)}
*
- {@link RestRequest#queryDataPairs(String...) queryDataPairs(String...)}
*
*
*
* Example:
*
* // Create a client that adds a ?foo=bar query parameter to every request.
* RestClient client = RestClient.create ().query("foo" , "bar" ).build();
*
* // Or do it on every request.
* String response = client .get(URI ).query("foo" , "bar" ).run().getContent().asString();
*
*
* Notes:
* - Like header values, dynamic values and OpenAPI schemas are supported.
*
- Methods that pass in POJOs convert values to strings using the part serializers. Methods that pass in
NameValuePair
* objects use the values returned by that bean directly.
*
*
*
* Request Form Data
*
*
* Per-client or per-request form-data parameters can be specified using the following methods:
*
* - {@link Builder}
*
* - {@link Builder#formData() formData()}
*
- {@link Builder#formData(String,String) formData(String,String)}
*
- {@link Builder#formData(String,Supplier) formData(String,Supplier<?>)}
*
- {@link Builder#formData(NameValuePair...) formDatas(NameValuePair...)}
*
- {@link Builder#formDataDefault(NameValuePair...) defaultFormData(NameValuePair...)}
*
* - {@link RestRequest}
*
* - {@link RestRequest#formData(String,Object) formData(String,Object)}
*
- {@link RestRequest#formData(NameValuePair...) formData(NameValuePair...)}
*
- {@link RestRequest#formDataBean(Object) formDataBean(Object)}
*
- {@link RestRequest#formDataCustom(Object) formDataCustom(Object)}
*
- {@link RestRequest#formDataPairs(String...) formDataPairs(String...)}
*
*
*
* Notes:
* - Like header values, dynamic values and OpenAPI schemas are supported.
*
- Methods that pass in POJOs convert values to strings using the part serializers. Methods that pass in
NameValuePair
* objects use the values returned by that bean directly.
*
*
*
* Request Body
*
*
* The request body can either be passed in with the client creator method (e.g. {@link RestClient#post(Object,Object) post(uri,body)}),
* or can be specified via the following methods:
*
*
* - {@link RestRequest}
*
* - {@link RestRequest#content(Object) body(Object)}
*
- {@link RestRequest#content(Object,HttpPartSchema) body(Object,HttpPartSchema)}
*
*
*
*
* The request body can be any of the following types:
*
* -
* {@link Object} - POJO to be converted to text using the {@link Serializer} defined on the client or request.
*
-
* {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource.
*
-
* {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource.
*
-
* {@link HttpResource} - Raw contents will be serialized to remote resource. Additional headers and media type will be set on request.
*
-
* {@link HttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient.
*
-
* {@link PartList} - Converted to a URL-encoded FORM post.
*
-
* {@link Supplier} - A supplier of anything on this list.
*
*
* Notes:
* - If the serializer on the client or request is explicitly set to
null , POJOs will be converted to strings
* using the registered part serializer as content type "text/plain . If the part serializer is also null ,
* POJOs will be converted to strings using {@link ClassMeta#toString(Object)} which typically just calls {@link Object#toString()}.
*
*
*
* Response Status
*
*
* After execution using {@link RestRequest#run()} or {@link RestRequest#complete()}, the following methods can be used
* to get the response status:
*
*
* - {@link RestResponse}
*
* {@link RestResponse#getStatusLine() getStatusLine()} returns {@link StatusLine}
* {@link RestResponse#getStatusCode() getStatusCode()} returns int
* {@link RestResponse#getReasonPhrase() getReasonPhrase()} returns String
* {@link RestResponse#assertStatus() assertStatus()} returns {@link FluentResponseStatusLineAssertion}
*
*
*
* Example:
*
* // Only interested in status code.
* int statusCode = client .get(URI ).complete().getStatusCode();
*
*
*
* Equivalent methods with mutable parameters are provided to allow access to status values without breaking fluent call chains.
*
*
Example:
*
* // Interested in multiple values.
* Value<Integer> statusCode = Value.create ();
* Value<String> reasonPhrase = Value.create ();
*
* client .get(URI ).complete().getStatusCode(statusCode ).getReasonPhrase(reasonPhrase );
* System.err .println("statusCode=" +statusCode .get()+", reasonPhrase=" +reasonPhrase .get());
*
*
* Notes:
* - If you are only interested in the response status and not the response body, be sure to use {@link RestRequest#complete()} instead
* of {@link RestRequest#run()} to make sure the response body gets automatically cleaned up. Otherwise you must
* consume the response yourself.
*
*
*
* The assertion method is provided for quickly asserting status codes in fluent calls.
*
*
Example:
*
* // Status assertion using a static value.
* String body = client .get(URI )
* .run()
* .assertStatus().asCode().isBetween(200,399)
* .getContent().asString();
*
* // Status assertion using a predicate.
* String body = client .get(URI )
* .run()
* .assertStatus().asCode().is(x -> x <400)
* .getContent().asString();
*
*
*
* Response Headers
*
*
* Response headers are accessed through the following methods:
*
*
* - {@link RestResponse}
*
* {@link RestResponse#getHeaders(String) getHeaders(String)} returns {@link ResponseHeader}[]
* {@link RestResponse#getFirstHeader(String) getFirstHeader(String)} returns {@link ResponseHeader}
* {@link RestResponse#getLastHeader(String) getLastHeader(String)} returns {@link ResponseHeader}
* {@link RestResponse#getAllHeaders() getAllHeaders()} returns {@link ResponseHeader}[]
* {@link RestResponse#getStringHeader(String) getStringHeader(String)} returns String
* {@link RestResponse#containsHeader(String) containsHeader(String)} returns boolean
*
*
*
*
* The {@link RestResponse#getFirstHeader(String)} and {@link RestResponse#getLastHeader(String)} methods return an empty {@link ResponseHeader} object instead ofnull .
* This allows it to be used more easily in fluent calls.
*
*
Example:
*
* // See if response contains Location header.
* boolean hasLocationHeader = client .get(URI ).complete().getLastHeader("Location" ).exists();
*
*
*
* The {@link ResponseHeader} class extends from the HttpClient {@link Header} class and provides several convenience
* methods:
*
*
* - {@link ResponseHeader}
*
* {@link ResponseHeader#isPresent() isPresent()} returns boolean
* {@link ResponseHeader#asString() asString()} returns String
* {@link ResponseHeader#as(Type,Type...) as(Type,Type...)} returns T
* {@link ResponseHeader#as(Class) as(Class<T>)} returns T
* {@link ResponseHeader#asMatcher(Pattern) asMatcher(Pattern)} returns {@link Matcher}
* {@link ResponseHeader#asMatcher(String) asMatcher(String)} returns {@link Matcher}
* {@link ResponseHeader#asHeader(Class) asHeader(Class<T extends BasicHeader> c)} returns {@link BasicHeader}
* {@link ResponseHeader#asStringHeader() asStringHeader()} returns {@link BasicStringHeader}
* {@link ResponseHeader#asIntegerHeader() asIntegerHeader()} returns {@link BasicIntegerHeader}
* {@link ResponseHeader#asLongHeader() asLongHeader()} returns {@link BasicLongHeader}
* {@link ResponseHeader#asDateHeader() asDateHeader()} returns {@link BasicDateHeader}
* {@link ResponseHeader#asCsvHeader() asCsvHeader()} returns {@link BasicCsvHeader}
* {@link ResponseHeader#asEntityTagsHeader() asEntityTagsHeader()} returns {@link BasicEntityTagsHeader}
* {@link ResponseHeader#asStringRangesHeader() asStringRangesHeader()} returns {@link BasicStringRangesHeader}
* {@link ResponseHeader#asUriHeader() asUriHeader()} returns {@link BasicUriHeader}
*
*
*
*
* The {@link ResponseHeader#schema(HttpPartSchema)} method allows you to perform parsing of OpenAPI formats for
* header parts.
*
*
Example:
*
* // Parse the header "Foo: bar|baz".
* List<String> fooHeader = client
* .get(URI )
* .complete()
* .getHeader("Foo" ).schema(T_ARRAY_PIPES ).as(List.class , String.class );
*
*
*
* Assertion methods are also provided for fluent-style calls:
*
*
* - {@link ResponseHeader}
*
* {@link ResponseHeader#assertValue() assertValue()} returns {@link FluentResponseHeaderAssertion}
*
*
*
*
* Note how in the following example, the fluent assertion returns control to the {@link RestResponse} object after
* the assertion has been completed:
*
*
Example:
*
* // Assert the response content type is any sort of JSON.
* String body = client .get(URI )
* .run()
* .getHeader("Content-Type" ).assertValue().matchesSimple("application/json*" )
* .getContent().asString();
*
*
*
* Response Body
*
*
* The response body is accessed through the following method:
*
*
* - {@link RestResponse}
*
* {@link RestResponse#getContent() getContent()} returns {@link ResponseContent}
*
*
*
*
* The {@link ResponseContent} class extends from the HttpClient {@link HttpEntity} class and provides several convenience
* methods:
*
*
* - {@link ResponseContent}
*
* {@link ResponseContent#asInputStream() asInputStream()} returns InputStream
* {@link ResponseContent#asReader() asReader()} returns Reader
* {@link ResponseContent#asReader(Charset) asReader(Charset)} returns Reader
* {@link ResponseContent#pipeTo(OutputStream) pipeTo(OutputStream)} returns {@link RestResponse}
* {@link ResponseContent#pipeTo(Writer) pipeTo(Writer)} returns {@link RestResponse}
* {@link ResponseContent#as(Type,Type...) as(Type,Type...)} returns T
* {@link ResponseContent#as(Class) as(Class<T>)} returns T
* {@link ResponseContent#asFuture(Class) asFuture(Class<T>)} returns Future<T>
* {@link ResponseContent#asFuture(Type,Type...) asFuture(Type,Type...)} returns Future<T>
* {@link ResponseContent#asString() asString()} returns String
* {@link ResponseContent#asStringFuture() asStringFuture()} returns Future<String>
* {@link ResponseContent#asAbbreviatedString(int) asAbbreviatedString(int)} returns String
* {@link ResponseContent#asObjectRest(Class) asObjectRest(Class<?>)} returns {@link ObjectRest}
* {@link ResponseContent#asObjectRest() asObjectRest()} returns {@link ObjectRest}
* {@link ResponseContent#asMatcher(Pattern) asMatcher(Pattern)} returns {@link Matcher}
* {@link ResponseContent#asMatcher(String) asMatcher(String)} returns {@link Matcher}
*
*
*
*
*
* Examples:
*
* // Parse into a linked-list of strings.
* List<String> list1 = client
* .get(URI )
* .run()
* .getContent().as(LinkedList.class , String.class );
*
* // Parse into a linked-list of beans.
* List<MyBean> list2 = client
* .get(URI )
* .run()
* .getContent().as(LinkedList.class , MyBean.class );
*
* // Parse into a linked-list of linked-lists of strings.
* List<List<String>> list3 = client
* .get(URI )
* .run()
* .getContent().as(LinkedList.class , LinkedList.class , String.class );
*
* // Parse into a map of string keys/values.
* Map<String,String> map1 = client
* .get(URI )
* .run()
* .getContent().as(TreeMap.class , String.class , String.class );
*
* // Parse into a map containing string keys and values of lists containing beans.
* Map<String,List<MyBean>> map2 = client
* .get(URI )
* .run()
* .getContent().as(TreeMap.class , String.class , List.class , MyBean.class );
*
*
*
* The response body can only be consumed once unless it has been cached into memory. In many cases, the body is
* automatically cached when using the assertions methods or methods such as {@link ResponseContent#asString()}.
* However, methods that involve reading directly from the input stream cannot be called twice.
* In these cases, the {@link RestResponse#cacheContent()} and {@link ResponseContent#cache()} methods are provided
* to cache the response body in memory so that you can perform several operations against it.
*
*
* // Cache the response body so we can access it twice.
* InputStream inputStream = client
* .get(URI )
* .run()
* .cacheBody()
* .getContent().pipeTo(someOtherStream )
* .getContent().asInputStream();
*
*
*
* Assertion methods are also provided for fluent-style calls:
*
*
* - {@link ResponseContent}
*
* {@link ResponseContent#assertValue() assertValue()} returns {@link FluentResponseBodyAssertion}
*
*
*
*
*
* Example:
*
* // Assert that the body contains the string "Success".
* String body = client
* .get(URI )
* .run()
* .getContent().assertString().contains("Success" )
* .getContent().asString();
*
*
*
* Object assertions allow you to parse the response body into a POJO and then perform various tests on that resulting
* POJO.
*
*
Example:
*
* // Parse bean into POJO and then validate that it was parsed correctly.
* MyBean bean = client .get(URI )
* .run()
* .getContent().assertObject(MyBean.class ).asJson().is("{foo:'bar'}" )
* .getContent().as(MyBean.class );
*
*
*
* Custom Call Handlers
*
*
* The {@link RestCallHandler} interface provides the ability to provide custom handling of requests.
*
*
* - {@link Builder}
*
* - {@link Builder#callHandler() callHandler()}
*
* - {@link RestCallHandler}
*
* {@link RestCallHandler#run(HttpHost,HttpRequest,HttpContext) run(HttpHost,HttpRequest,HttpContext)} returns HttpResponse
*
*
*
*
* Note that there are other ways of accomplishing this such as extending the {@link RestClient} class and overriding
* the {@link #run(HttpHost,HttpRequest,HttpContext)} method
* or by defining your own {@link HttpRequestExecutor}. Using this interface is often simpler though.
*
*
*
Interceptors
*
*
* The {@link RestCallInterceptor} API provides a quick way of intercepting and manipulating requests and responses beyond
* the existing {@link HttpRequestInterceptor} and {@link HttpResponseInterceptor} APIs.
*
*
* - {@link Builder}
*
* - {@link Builder#interceptors(Object...) interceptors(Object...)}
*
* - {@link RestRequest}
*
* - {@link RestRequest#interceptors(RestCallInterceptor...) interceptors(RestCallInterceptor...)}
*
* - {@link RestCallInterceptor}
*
* - {@link RestCallInterceptor#onInit(RestRequest) onInit(RestRequest)}
*
- {@link RestCallInterceptor#onConnect(RestRequest,RestResponse) onConnect(RestRequest,RestResponse)}
*
- {@link RestCallInterceptor#onClose(RestRequest,RestResponse) onClose(RestRequest,RestResponse)}
*
*
*
*
* Logging / Debugging
*
*
* The following methods provide logging of requests and responses:
*
*
* - {@link Builder}
*
* - {@link Builder#logger(Logger) logger(Logger)}
*
- {@link Builder#logToConsole() logToConsole()}
*
- {@link Builder#logRequests(DetailLevel,Level,BiPredicate) logRequests(DetailLevel,Level,BiPredicate)}
*
*
*
*
* The following example shows the results of logging all requests that end with /bean .
*
*
Examples:
*
* MyBean bean = RestClient
* .create ()
* .json5()
* .logRequests(DetailLevel.FULL , Level.SEVERE , (req ,res )->req .getUri().endsWith("/bean" ))
* .logToConsole()
* .build()
* .post("http://localhost/bean" , anotherBean )
* .run()
* .getContent().as(MyBean.class );
*
*
*
* This produces the following console output:
*
*
* === HTTP Call (outgoing) ======================================================
* === REQUEST ===
* POST http://localhost/bean
* ---request headers---
* Accept: application/json5
* ---request entity---
* Content-Type: application/json5
* ---request content---
* {f:1}
* === RESPONSE ===
* HTTP/1.1 200
* ---response headers---
* Content-Type: application/json
* ---response content---
* {f:1}
* === END =======================================================================",
*
*
*
*
* It should be noted that if you enable request logging detail level {@link DetailLevel#FULL}, response bodies will be cached by default which may introduce
* a performance penalty.
*
*
* Additionally, the following method is also provided for enabling debug mode:
*
*
* - {@link Builder}
*
* - {@link Builder#debug() debug()}
*
*
*
*
* Enabling debug mode has the following effects:
*
* - {@link org.apache.juneau.Context.Builder#debug()} is enabled.
*
- {@link Builder#detectLeaks()} is enabled.
*
- {@link Builder#logToConsole()} is called.
*
*
*
* REST Proxies
*
*
* One of the more powerful features of the REST client class is the ability to produce Java interface proxies against
* arbitrary remote REST resources.
*
*
Example:
*
* // Define a Remote proxy for interacting with a REST interface.
* @Remote (path="/petstore" )
* public interface PetStore {
*
* @RemotePost ("/pets" )
* Pet addPet(
* @Content CreatePet pet ,
* @Header ("E-Tag" ) UUID etag ,
* @Query ("debug" ) boolean debug
* );
* }
*
* // Use a RestClient with default JSON 5 support.
* RestClient client = RestClient.create ().json5().build())
*
* PetStore store = client .getRemote(PetStore.class , "http://localhost:10000" );
* CreatePet createPet = new CreatePet("Fluffy" , 9.99);
* Pet pet = store .addPet(createPet , UUID.randomUUID (), true );
*
*
*
* The methods to retrieve remote interfaces are:
*
*
* - {@link RestClient}
*
* {@link RestClient#getRemote(Class) getRemote(Class<T>)} returns T
* {@link RestClient#getRemote(Class,Object) getRemote(Class<T>,Object)} returns T
* {@link RestClient#getRemote(Class,Object,Serializer,Parser) getRemote(Class<T>,Object,Serializer,Parser)} returns T
* {@link RestClient#getRrpcInterface(Class) getRrpcInterface(Class<T>)} returns T
* {@link RestClient#getRrpcInterface(Class,Object) getRrpcInterface(Class<T>,Object)} returns T
* {@link RestClient#getRrpcInterface(Class,Object,Serializer,Parser) getRrpcInterface(Class<T>,Object,Serializer,Parser)} returns T
*
*
*
*
* Two basic types of remote interfaces are provided:
*
*
* - {@link Remote @Remote}-annotated interfaces. These can be defined against arbitrary external REST resources.
*
- RPC-over-REST interfaces. These are Java interfaces that allow you to make method calls on server-side POJOs.
*
*
*
* Refer to the following documentation on both flavors:
*
*
* - REST Proxies
*
- REST/RPC
*
*
*
*
* Customizing Apache HttpClient
*
*
* Several methods are provided for customizing the underlying HTTP client and client builder classes:
*
* - {@link Builder}
*
* - {@link Builder#httpClientBuilder(HttpClientBuilder) httpClientBuilder(HttpClientBuilder)} - Set the client builder yourself.
*
- {@link Builder#createHttpClientBuilder() createHttpClientBuilder()} - Override to create the client builder.
*
- {@link Builder#createHttpClient() createHttpClient()} - Override to create the client.
*
- {@link Builder#createConnectionManager() createConnectionManager()} - Override to create the connection management.
*
*
*
*
* Additionally, all methods on the HttpClientBuilder class have been extended with fluent setters.
*
*
Example:
*
* // Create a client with customized HttpClient settings.
* MyBean bean = RestClient
* .create ()
* .disableRedirectHandling()
* .connectionManager(myConnectionManager )
* .addInterceptorFirst(myHttpRequestInterceptor )
* .build();
*
*
*
* Refer to the {@link HttpClientBuilder HTTP Client Builder API} for more information.
*
*
*
Extending RestClient
*
*
* The RestClient API has been designed to allow for the ability to be easily extended.
* The following example that overrides the primary run method shows how this can be done.
*
*
Example:
*
* public class MyRestClient extends RestClient {
*
* // Must provide this constructor!
* public MyRestClient(RestClient.Builder builder ) {
* super (builder );
* }
*
* /** Optionally override to customize builder settings before initialization.
* @Override
* protected void init(RestClient.Builder) {...}
*
* /** Optionally override to provide post-initialization (e.g. setting up SAML handshakes, etc...).
* @Override
* protected void init() {...}
*
* /** Optionally override to customize requests when they're created (e.g. add headers to each request).
* @Override
* protected RestRequest request(RestOperation) {...}
*
* /** Optionally override to implement your own call handling.
* @Override
* protected HttpResponse run(HttpHost, HttpRequest, HttpContext) {...}
*
* /** Optionally override to customize requests before they're executed.
* @Override
* protected void onCallInit(RestRequest) {...}
*
* /** Optionally override to customize responses as soon as a connection is made.
* @Override
* protected void onCallConnect(RestRequest, RestResponse) {...}
*
* /** Optionally override to perform any call cleanup.
* @Override
* protected void onCallClose(RestRequest, RestResponse) {...}
* }
*
* // Instantiate your client.
* MyRestClient client = RestClient.create ().json().build(MyRestClient.class );
*
*
*
* The {@link RestRequest} and {@link RestResponse} objects can also be extended and integrated by overriding the
* {@link RestClient#createRequest(URI,String,boolean)} and {@link RestClient#createResponse(RestRequest,HttpResponse,Parser)} methods.
*
*
Notes:
* - This class is thread safe and reusable.
*
*
* See Also:
*/
public class RestClient extends BeanContextable implements HttpClient, Closeable {
//-------------------------------------------------------------------------------------------------------------------
// Static
//-------------------------------------------------------------------------------------------------------------------
private static final RestCallInterceptor[] EMPTY_REST_CALL_INTERCEPTORS = {};
/**
* Instantiates a new clean-slate {@link Builder} object.
*
* @return A new {@link Builder} object.
*/
public static Builder create() {
return new Builder();
}
//-------------------------------------------------------------------------------------------------------------------
// Builder
//-------------------------------------------------------------------------------------------------------------------
/**
* Builder class.
*/
@FluentSetters(ignore={"beanMapPutReturnsOldValue","example","exampleJson","debug","mediaType"})
public static class Builder extends BeanContextable.Builder {
BeanStore beanStore = BeanStore.create().build();
private HttpClientBuilder httpClientBuilder;
private CloseableHttpClient httpClient;
private HeaderList headerData;
private PartList queryData, formData, pathData;
private BeanCreator callHandler;
private SerializerSet.Builder serializers;
private ParserSet.Builder parsers;
private HttpPartSerializer.Creator partSerializer;
private HttpPartParser.Creator partParser;
private UrlEncodingSerializer.Builder urlEncodingSerializer;
private boolean pooled;
String rootUrl;
boolean skipEmptyHeaderData, skipEmptyFormData, skipEmptyQueryData, executorServiceShutdownOnClose, ignoreErrors, keepHttpClientOpen, detectLeaks,
logToConsole;
Logger logger;
DetailLevel logRequests;
Level logRequestsLevel;
BiPredicate logRequestsPredicate;
Predicate errorCodes = x -> x<=0 || x>=400;
HttpClientConnectionManager connectionManager;
PrintStream console;
ExecutorService executorService;
List interceptors;
/**
* Constructor.
*/
protected Builder() {
}
@Override /* Context.Builder */
public Builder copy() {
throw new NoSuchMethodError("Not implemented.");
}
@Override /* Context.Builder */
public RestClient build() {
return build(RestClient.class);
}
//------------------------------------------------------------------------------------------------------------------
// Convenience marshalling support methods.
//------------------------------------------------------------------------------------------------------------------
/**
* Convenience method for specifying JSON as the marshalling transmission media type.
*
*
* {@link JsonSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
*
* - The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* {@link JsonParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
*
* - The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* Accept request header will be set to "application/json" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}}.
*
* Content-Type request header will be set to "application/json" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Can be combined with other marshaller setters such as {@link #xml()} to provide support for multiple languages.
*
* - When multiple languages are supported, the
Accept and Content-Type headers control which marshallers are used, or uses the
* last-enabled language if the headers are not set.
*
*
* Identical to calling serializer(JsonSerializer.class ).parser(JsonParser.class ) .
*
*
Example:
*
* // Construct a client that uses JSON marshalling.
* RestClient client = RestClient.create ().json().build();
*
*
* @return This object.
*/
@FluentSetter
public Builder json() {
return serializer(JsonSerializer.class).parser(JsonParser.class);
}
/**
* Convenience method for specifying Simplified JSON as the marshalling transmission media type.
*
*
* Simplified JSON is typically useful for automated tests because you can do simple string comparison of results
* without having to escape lots of quotes.
*
*
* {@link Json5Serializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
*
* - The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* {@link Json5Parser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
*
* - The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* Accept request header will be set to "application/json" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Content-Type request header will be set to "application/json5" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Can be combined with other marshaller setters such as {@link #xml()} to provide support for multiple languages.
*
* - When multiple languages are supported, the
Accept and Content-Type headers control which marshallers are used, or uses the
* last-enabled language if the headers are not set.
*
*
* Identical to calling serializer(Json5Serializer.class ).parser(Json5Parser.class ) .
*
*
Example:
*
* // Construct a client that uses Simplified JSON marshalling.
* RestClient client = RestClient.create ().json5().build();
*
*
* @return This object.
*/
@FluentSetter
public Builder json5() {
return serializer(Json5Serializer.class).parser(Json5Parser.class);
}
/**
* Convenience method for specifying XML as the marshalling transmission media type.
*
*
* {@link XmlSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
*
* - The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* {@link XmlParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
*
* - The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* Accept request header will be set to "text/xml" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Content-Type request header will be set to "text/xml" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Can be combined with other marshaller setters such as {@link #json()} to provide support for multiple languages.
*
* - When multiple languages are supported, the
Accept and Content-Type headers control which marshallers are used, or uses the
* last-enabled language if the headers are not set.
*
*
* Identical to calling serializer(XmlSerializer.class ).parser(XmlParser.class ) .
*
*
Example:
*
* // Construct a client that uses XML marshalling.
* RestClient client = RestClient.create ().xml().build();
*
*
* @return This object.
*/
@FluentSetter
public Builder xml() {
return serializer(XmlSerializer.class).parser(XmlParser.class);
}
/**
* Convenience method for specifying HTML as the marshalling transmission media type.
*
*
* POJOs are converted to HTML without any sort of doc wrappers.
*
*
* {@link HtmlSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
*
* - The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* {@link HtmlParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
*
* - The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* Accept request header will be set to "text/html" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Content-Type request header will be set to "text/html" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Can be combined with other marshaller setters such as {@link #json()} to provide support for multiple languages.
*
* - When multiple languages are supported, the
Accept and Content-Type headers control which marshallers are used, or uses the
* last-enabled language if the headers are not set.
*
*
* Identical to calling serializer(HtmlSerializer.class ).parser(HtmlParser.class ) .
*
*
Example:
*
* // Construct a client that uses HTML marshalling.
* RestClient client = RestClient.create ().html().build();
*
*
* @return This object.
*/
@FluentSetter
public Builder html() {
return serializer(HtmlSerializer.class).parser(HtmlParser.class);
}
/**
* Convenience method for specifying HTML DOC as the marshalling transmission media type.
*
*
* POJOs are converted to fully renderable HTML pages.
*
*
* {@link HtmlDocSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
*
* - The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()} or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* {@link HtmlParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
*
* - The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* Accept request header will be set to "text/html" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Content-Type request header will be set to "text/html" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Can be combined with other marshaller setters such as {@link #json()} to provide support for multiple languages.
*
* - When multiple languages are supported, the
Accept and Content-Type headers control which marshallers are used, or uses the
* last-enabled language if the headers are not set.
*
*
* Identical to calling serializer(HtmlDocSerializer.class ).parser(HtmlParser.class ) .
*
*
Example:
*
* // Construct a client that uses HTML Doc marshalling.
* RestClient client = RestClient.create ().htmlDoc().build();
*
*
* @return This object.
*/
@FluentSetter
public Builder htmlDoc() {
return serializer(HtmlDocSerializer.class).parser(HtmlParser.class);
}
/**
* Convenience method for specifying Stripped HTML DOC as the marshalling transmission media type.
*
*
* Same as {@link #htmlDoc()} but without the header and body tags and page title and description.
*
*
* {@link HtmlStrippedDocSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
*
* - The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* {@link HtmlParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
*
* - The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* Accept request header will be set to "text/html+stripped" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Content-Type request header will be set to "text/html+stripped" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Can be combined with other marshaller setters such as {@link #json()} to provide support for multiple languages.
*
* - When multiple languages are supported, the
Accept and Content-Type headers control which marshallers are used, or uses the
* last-enabled language if the headers are not set.
*
*
* Identical to calling serializer(HtmlStrippedDocSerializer.class ).parser(HtmlParser.class ) .
*
*
Example:
*
* // Construct a client that uses HTML Stripped Doc marshalling.
* RestClient client = RestClient.create ().htmlStrippedDoc().build();
*
*
* @return This object.
*/
@FluentSetter
public Builder htmlStrippedDoc() {
return serializer(HtmlStrippedDocSerializer.class).parser(HtmlParser.class);
}
/**
* Convenience method for specifying Plain Text as the marshalling transmission media type.
*
*
* Plain text marshalling typically only works on simple POJOs that can be converted to and from strings using
* swaps, swap methods, etc...
*
*
* {@link PlainTextSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
*
* - The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* {@link PlainTextParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
*
* - The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* Accept request header will be set to "text/plain" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Content-Type request header will be set to "text/plain" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Can be combined with other marshaller setters such as {@link #json()} to provide support for multiple languages.
*
* - When multiple languages are supported, the
Accept and Content-Type headers control which marshallers are used, or uses the
* last-enabled language if the headers are not set.
*
*
* Identical to calling serializer(PlainTextSerializer.class ).parser(PlainTextParser.class ) .
*
*
Example:
*
* // Construct a client that uses Plain Text marshalling.
* RestClient client = RestClient.create ().plainText().build();
*
*
* @return This object.
*/
@FluentSetter
public Builder plainText() {
return serializer(PlainTextSerializer.class).parser(PlainTextParser.class);
}
/**
* Convenience method for specifying MessagePack as the marshalling transmission media type.
*
*
* MessagePack is a binary equivalent to JSON that takes up considerably less space than JSON.
*
*
* {@link MsgPackSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
*
* - The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* {@link MsgPackParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
*
* - The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* Accept request header will be set to "octal/msgpack" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Content-Type request header will be set to "octal/msgpack" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Can be combined with other marshaller setters such as {@link #json()} to provide support for multiple languages.
*
* - When multiple languages are supported, the
Accept and Content-Type headers control which marshallers are used, or uses the
* last-enabled language if the headers are not set.
*
*
* Identical to calling serializer(MsgPackSerializer.class ).parser(MsgPackParser.class ) .
*
*
Example:
*
* // Construct a client that uses MessagePack marshalling.
* RestClient client = RestClient.create ().msgPack().build();
*
*
* @return This object.
*/
@FluentSetter
public Builder msgPack() {
return serializer(MsgPackSerializer.class).parser(MsgPackParser.class);
}
/**
* Convenience method for specifying UON as the marshalling transmission media type.
*
*
* UON is Url-Encoding Object notation that is equivalent to JSON but suitable for transmission as URL-encoded
* query and form post values.
*
*
* {@link UonSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
*
* - The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* {@link UonParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
*
* - The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* Accept request header will be set to "text/uon" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Content-Type request header will be set to "text/uon" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Can be combined with other marshaller setters such as {@link #json()} to provide support for multiple languages.
*
* - When multiple languages are supported, the
Accept and Content-Type headers control which marshallers are used, or uses the
* last-enabled language if the headers are not set.
*
*
* Identical to calling serializer(UonSerializer.class ).parser(UonParser.class ) .
*
*
Example:
*
* // Construct a client that uses UON marshalling.
* RestClient client = RestClient.create ().uon().build();
*
*
* @return This object.
*/
@FluentSetter
public Builder uon() {
return serializer(UonSerializer.class).parser(UonParser.class);
}
/**
* Convenience method for specifying URL-Encoding as the marshalling transmission media type.
*
*
* {@link UrlEncodingSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
*
* - The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
- This serializer is NOT used when using the {@link RestRequest#formData(String, Object)} (and related) methods for constructing
* the request body. Instead, the part serializer specified via {@link #partSerializer(Class)} is used.
*
*
* {@link UrlEncodingParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
*
* - The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* Accept request header will be set to "application/x-www-form-urlencoded" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Content-Type request header will be set to "application/x-www-form-urlencoded" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Can be combined with other marshaller setters such as {@link #json()} to provide support for multiple languages.
*
* - When multiple languages are supported, the
Accept and Content-Type headers control which marshallers are used, or uses the
* last-enabled language if the headers are not set.
*
*
* Identical to calling serializer(UrlEncodingSerializer.class ).parser(UrlEncodingParser.class ) .
*
*
Example:
*
* // Construct a client that uses URL-Encoded marshalling.
* RestClient client = RestClient.create ().urlEnc().build();
*
*
* @return This object.
*/
@FluentSetter
public Builder urlEnc() {
return serializer(UrlEncodingSerializer.class).parser(UrlEncodingParser.class);
}
/**
* Convenience method for specifying OpenAPI as the marshalling transmission media type.
*
*
* OpenAPI is a language that allows serialization to formats that use {@link HttpPartSchema} objects to describe their structure.
*
*
* {@link OpenApiSerializer} will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
*
* - The serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
- Typically the {@link RestRequest#content(Object, HttpPartSchema)} method will be used to specify the body of the request with the
* schema describing it's structure.
*
*
* {@link OpenApiParser} will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
*
* - The parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
- Typically the {@link ResponseContent#schema(HttpPartSchema)} method will be used to specify the structure of the response body.
*
*
* Accept request header will be set to "text/openapi" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Content-Type request header will be set to "text/openapi" unless overridden
* via {@link #headers()}, or per-request via {@link RestRequest#header(Header)}.
*
* Can be combined with other marshaller setters such as {@link #json()} to provide support for multiple languages.
*
* - When multiple languages are supported, the
Accept and Content-Type headers control which marshallers are used, or uses the
* last-enabled language if the headers are not set.
*
*
* Identical to calling serializer(OpenApiSerializer.class ).parser(OpenApiParser.class ) .
*
*
Example:
*
* // Construct a client that uses OpenAPI marshalling.
* RestClient client = RestClient.create ().openApi().build();
*
*
* @return This object.
*/
@FluentSetter
public Builder openApi() {
return serializer(OpenApiSerializer.class).parser(OpenApiParser.class);
}
/**
* Convenience method for specifying all available transmission types.
*
*
* All basic Juneau serializers will be used to serialize POJOs to request bodies unless overridden per request via {@link RestRequest#serializer(Serializer)}.
*
* - The serializers can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* All basic Juneau parsers will be used to parse POJOs from response bodies unless overridden per request via {@link RestRequest#parser(Parser)}.
*
* - The parsers can be configured using any of the parser property setters (e.g. {@link #strict()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* Accept request header must be set via {@link #headers()}, or per-request
* via {@link RestRequest#header(Header)} in order for the correct parser to be selected.
*
* Content-Type request header must be set via {@link #headers()},
* or per-request via {@link RestRequest#header(Header)} in order for the correct serializer to be selected.
*
* Similar to calling json().json5().html().xml().uon().urlEnc().openApi().msgPack().plainText() .
*
*
Example:
*
* // Construct a client that uses universal marshalling.
* RestClient client = RestClient.create ().universal().build();
*
*
* @return This object.
*/
@SuppressWarnings("unchecked")
public Builder universal() {
return
serializers(
JsonSerializer.class,
Json5Serializer.class,
HtmlSerializer.class,
XmlSerializer.class,
UonSerializer.class,
UrlEncodingSerializer.class,
OpenApiSerializer.class,
MsgPackSerializer.class,
PlainTextSerializer.class
)
.parsers(
JsonParser.class,
Json5Parser.class,
XmlParser.class,
HtmlParser.class,
UonParser.class,
UrlEncodingParser.class,
OpenApiParser.class,
MsgPackParser.class,
PlainTextParser.class
);
}
//------------------------------------------------------------------------------------------------------------------
// httpClientBuilder
//------------------------------------------------------------------------------------------------------------------
/**
* Returns the HTTP client builder.
*
* @return The HTTP client builder.
*/
public final HttpClientBuilder httpClientBuilder() {
if (httpClientBuilder == null)
httpClientBuilder = createHttpClientBuilder();
return httpClientBuilder;
}
/**
* Creates an instance of an {@link HttpClientBuilder} to be used to create the {@link HttpClient}.
*
*
* Subclasses can override this method to provide their own client builder.
* The builder can also be specified using the {@link #httpClientBuilder(HttpClientBuilder)} method.
*
*
Example:
*
* // A Builder that provides it's own customized HttpClientBuilder.
* public class MyBuilder extends Builder {
* @Override
* protected HttpClientBuilder createHttpClientBuilder() {
* return HttpClientBuilder.create ();
* }
* }
*
* // Instantiate.
* RestClient client = new MyBuilder().build();
*
*
* @return The HTTP client builder to use to create the HTTP client.
*/
protected HttpClientBuilder createHttpClientBuilder() {
return HttpClientBuilder.create();
}
/**
* Sets the {@link HttpClientBuilder} that will be used to create the {@link HttpClient} used by {@link RestClient}.
*
*
* This can be used to bypass the builder created by {@link #createHttpClientBuilder()} method.
*
*
Example:
*
* // Construct a client that uses a customized HttpClientBuilder.
* RestClient client = RestClient
* .create ()
* .httpClientBuilder(HttpClientBuilder.create ())
* .build();
*
*
* @param value The {@link HttpClientBuilder} that will be used to create the {@link HttpClient} used by {@link RestClient}.
* @return This object.
*/
@FluentSetter
public Builder httpClientBuilder(HttpClientBuilder value) {
this.httpClientBuilder = value;
return this;
}
//------------------------------------------------------------------------------------------------------------------
// httpClient
//------------------------------------------------------------------------------------------------------------------
/**
* Creates an instance of an {@link HttpClient} to be used to handle all HTTP communications with the target server.
*
*
* This HTTP client is used when the HTTP client is not specified through one of the constructors or the
* {@link #httpClient(CloseableHttpClient)} method.
*
*
* Subclasses can override this method to provide specially-configured HTTP clients to handle stuff such as
* SSL/TLS certificate handling, authentication, etc.
*
*
* The default implementation returns an instance of {@link HttpClient} using the client builder returned by
* {@link #createHttpClientBuilder()}.
*
*
Example:
*
* // A Builder that provides it's own customized HttpClient.
* public class MyBuilder extends Builder {
* @Override
* protected HttpClientBuilder createHttpClient() {
* return HttpClientBuilder.create ().build();
* }
* }
*
* // Instantiate.
* RestClient client = new MyBuilder().build();
*
*
* @return The HTTP client to use.
*/
protected CloseableHttpClient createHttpClient() {
if (connectionManager == null)
connectionManager = createConnectionManager();
httpClientBuilder().setConnectionManager(connectionManager);
return httpClientBuilder().build();
}
/**
* Sets the {@link HttpClient} to be used to handle all HTTP communications with the target server.
*
*
* This can be used to bypass the client created by {@link #createHttpClient()} method.
*
*
Example:
*
* // Construct a client that uses a customized HttpClient.
* RestClient client = RestClient
* .create ()
* .httpClient(HttpClientBuilder.create ().build())
* .build();
*
*
* @param value The {@link HttpClient} to be used to handle all HTTP communications with the target server.
* @return This object.
*/
@FluentSetter
public Builder httpClient(CloseableHttpClient value) {
this.httpClient = value;
return this;
}
final CloseableHttpClient getHttpClient() {
return httpClient != null ? httpClient : createHttpClient();
}
//------------------------------------------------------------------------------------------------------------------
// serializers
//------------------------------------------------------------------------------------------------------------------
/**
* Returns the serializer group sub-builder.
*
* @return The serializer group sub-builder.
*/
public final SerializerSet.Builder serializers() {
if (serializers == null)
serializers = createSerializers();
return serializers;
}
/**
* Instantiates the serializer group sub-builder.
*
* @return A new serializer group sub-builder.
*/
protected SerializerSet.Builder createSerializers() {
return SerializerSet.create().beanContext(beanContext());
}
/**
* Serializer.
*
*
* Associates the specified {@link Serializer Serializer} with the HTTP client.
*
*
* The serializer is used to serialize POJOs into the HTTP request body.
*
*
Notes:
* - When using this method that takes in a class, the serializer can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* Example:
*
* // Create a client that uses JSON transport for request bodies.
* RestClient client = RestClient
* .create ()
* .serializer(JsonSerializer.class )
* .sortCollections() // Sort any collections being serialized.
* .build();
*
*
* @param value
* The new value for this setting.
*
The default is {@link JsonSerializer}.
* @return This object.
*/
@SuppressWarnings("unchecked")
@FluentSetter
public Builder serializer(Class extends Serializer> value) {
return serializers(value);
}
/**
* Serializer.
*
*
* Associates the specified {@link Serializer Serializer} with the HTTP client.
*
*
* The serializer is used to serialize POJOs into the HTTP request body.
*
*
Notes:
* - When using this method that takes in a pre-instantiated serializer, the serializer property setters (e.g. {@link #sortCollections()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined
* on this builder class have no effect.
*
*
* Example:
*
* // Create a client that uses a predefined JSON serializer request bodies.
* RestClient client = RestClient
* .create ()
* .serializer(JsonSerializer.DEFAULT_READABLE )
* .build();
*
*
* @param value
* The new value for this setting.
*
The default is {@link JsonSerializer}.
* @return This object.
*/
@FluentSetter
public Builder serializer(Serializer value) {
return serializers(value);
}
/**
* Serializers.
*
*
* Associates the specified {@link Serializer Serializers} with the HTTP client.
*
*
* The serializer is used to serialize POJOs into the HTTP request body.
*
*
* The serializer that best matches the Content-Type header will be used to serialize the request body.
*
If no Content-Type header is specified, the first serializer in the list will be used.
*
*
Notes:
* - When using this method that takes in classes, the serializers can be configured using any of the serializer property setters (e.g. {@link #sortCollections()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* Example:
*
* // Create a client that uses JSON and XML transport for request bodies.
* RestClient client = RestClient
* .create ()
* .serializers(JsonSerializer.class , XmlSerializer.class )
* .sortCollections() // Sort any collections being serialized.
* .build();
*
*
* @param value
* The new value for this setting.
*
The default is {@link JsonSerializer}.
* @return This object.
*/
@SuppressWarnings("unchecked")
@FluentSetter
public Builder serializers(Class extends Serializer>...value) {
serializers().add(value);
return this;
}
/**
* Serializers.
*
*
* Associates the specified {@link Serializer Serializers} with the HTTP client.
*
*
* The serializer is used to serialize POJOs into the HTTP request body.
*
*
* The serializer that best matches the Content-Type header will be used to serialize the request body.
*
If no Content-Type header is specified, the first serializer in the list will be used.
*
*
Notes:
* - When using this method that takes in a pre-instantiated serializers, the serializer property setters (e.g. {@link #sortCollections()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined
* on this builder class have no effect.
*
*
* Example:
*
* // Create a client that uses predefined JSON and XML serializers for request bodies.
* RestClient client = RestClient
* .create ()
* .serializers(JsonSerializer.DEFAULT_READABLE , XmlSerializer.DEFAULT_READABLE )
* .build();
*
*
* @param value
* The new value for this setting.
*
The default is {@link JsonSerializer}.
* @return This object.
*/
@FluentSetter
public Builder serializers(Serializer...value) {
serializers().add(value);
return this;
}
//------------------------------------------------------------------------------------------------------------------
// parsers
//------------------------------------------------------------------------------------------------------------------
/**
* Returns the parser group sub-builder.
*
* @return The parser group sub-builder.
*/
public final ParserSet.Builder parsers() {
if (parsers == null)
parsers = createParsers();
return parsers;
}
/**
* Instantiates the parser group sub-builder.
*
* @return A new parser group sub-builder.
*/
protected ParserSet.Builder createParsers() {
return ParserSet.create().beanContext(beanContext());
}
/**
* Parser.
*
*
* Associates the specified {@link Parser Parser} with the HTTP client.
*
*
* The parser is used to parse the HTTP response body into a POJO.
*
*
Notes:
* - When using this method that takes in a class, the parser can be configured using any of the parser property setters (e.g. {@link #strict()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* Example:
*
* // Create a client that uses JSON transport for response bodies.
* RestClient client = RestClient
* .create ()
* .parser(JsonParser.class )
* .strict() // Enable strict mode on JsonParser.
* .build();
*
*
* @param value
* The new value for this setting.
*
The default value is {@link JsonParser#DEFAULT}.
* @return This object.
*/
@SuppressWarnings("unchecked")
@FluentSetter
public Builder parser(Class extends Parser> value) {
return parsers(value);
}
/**
* Parser.
*
*
* Associates the specified {@link Parser Parser} with the HTTP client.
*
*
* The parser is used to parse the HTTP response body into a POJO.
*
*
Notes:
* - When using this method that takes in a pre-instantiated parser, the parser property setters (e.g. {@link #strict()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined
* on this builder class have no effect.
*
*
* Example:
*
* // Create a client that uses a predefined JSON parser for response bodies.
* RestClient client = RestClient
* .create ()
* .parser(JsonParser.DEFAULT_STRICT )
* .build();
*
*
* @param value
* The new value for this setting.
*
The default value is {@link JsonParser#DEFAULT}.
* @return This object.
*/
@FluentSetter
public Builder parser(Parser value) {
return parsers(value);
}
/**
* Parsers.
*
*
* Associates the specified {@link Parser Parsers} with the HTTP client.
*
*
* The parsers are used to parse the HTTP response body into a POJO.
*
*
* The parser that best matches the Accept header will be used to parse the response body.
*
If no Accept header is specified, the first parser in the list will be used.
*
*
Notes:
* - When using this method that takes in classes, the parsers can be configured using any of the parser property setters (e.g. {@link #strict()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class.
*
*
* Example:
*
* // Create a client that uses JSON and XML transport for response bodies.
* RestClient client = RestClient
* .create ()
* .parser(JsonParser.class , XmlParser.class )
* .strict() // Enable strict mode on parsers.
* .build();
*
*
* @param value
* The new value for this setting.
*
The default value is {@link JsonParser#DEFAULT}.
* @return This object.
*/
@SuppressWarnings("unchecked")
@FluentSetter
public Builder parsers(Class extends Parser>...value) {
parsers().add(value);
return this;
}
/**
* Parsers.
*
*
* Associates the specified {@link Parser Parsers} with the HTTP client.
*
*
* The parsers are used to parse the HTTP response body into a POJO.
*
*
* The parser that best matches the Accept header will be used to parse the response body.
*
If no Accept header is specified, the first parser in the list will be used.
*
*
Notes:
* - When using this method that takes in pre-instantiated parsers, the parser property setters (e.g. {@link #strict()}) or
* bean context property setters (e.g. {@link #swaps(Class...)}) defined
* on this builder class have no effect.
*
*
* Example:
*
* // Create a client that uses JSON and XML transport for response bodies.
* RestClient client = RestClient
* .create ()
* .parser(JsonParser.DEFAULT_STRICT , XmlParser.DEFAULT )
* .build();
*
*
* @param value
* The new value for this setting.
*
The default value is {@link JsonParser#DEFAULT}.
* @return This object.
*/
@FluentSetter
public Builder parsers(Parser...value) {
parsers().add(value);
return this;
}
//------------------------------------------------------------------------------------------------------------------
// partSerializer
//------------------------------------------------------------------------------------------------------------------
/**
* Returns the part serializer sub-builder.
*
* @return The part serializer sub-builder.
*/
public final HttpPartSerializer.Creator partSerializer() {
if (partSerializer == null)
partSerializer = createPartSerializer();
return partSerializer;
}
/**
* Instantiates the part serializer sub-builder.
*
* @return A new part serializer sub-builder.
*/
protected HttpPartSerializer.Creator createPartSerializer() {
return HttpPartSerializer.creator().type(OpenApiSerializer.class).beanContext(beanContext());
}
/**
* Part serializer.
*
*
* The serializer to use for serializing POJOs in form data, query parameters, headers, and path variables.
*
*
* The default part serializer is {@link OpenApiSerializer} which allows for schema-driven marshalling.
*
*
Example:
*
* // Create a client that uses UON format by default for outgoing HTTP parts.
* RestClient client = RestClient
* .create ()
* .partSerializer(UonSerializer.class )
* .build();
*
*
* @param value
* The new value for this setting.
*
The default value is {@link OpenApiSerializer}.
* @return This object.
*/
@FluentSetter
public Builder partSerializer(Class extends HttpPartSerializer> value) {
partSerializer().type(value);
return this;
}
/**
* Part serializer.
*
*
* The serializer to use for serializing POJOs in form data, query parameters, headers, and path variables.
*
*
* The default part serializer is {@link OpenApiSerializer} which allows for schema-driven marshalling.
*
*
Example:
*
* // Create a client that uses UON format by default for outgoing HTTP parts.
* RestClient client = RestClient
* .create ()
* .partSerializer(UonSerializer.DEFAULT )
* .build();
*
*
* @param value
* The new value for this setting.
*
The default value is {@link OpenApiSerializer}.
* @return This object.
*/
@FluentSetter
public Builder partSerializer(HttpPartSerializer value) {
partSerializer().impl(value);
return this;
}
//------------------------------------------------------------------------------------------------------------------
// partParser
//------------------------------------------------------------------------------------------------------------------
/**
* Returns the part parser sub-builder.
*
* @return The part parser sub-builder.
*/
public final HttpPartParser.Creator partParser() {
if (partParser == null)
partParser = createPartParser();
return partParser;
}
/**
* Instantiates the part parser sub-builder.
*
* @return A new part parser sub-builder.
*/
protected HttpPartParser.Creator createPartParser() {
return HttpPartParser.creator().type(OpenApiParser.class).beanContext(beanContext());
}
/**
* Part parser.
*
*
* The parser to use for parsing POJOs from form data, query parameters, headers, and path variables.
*
*
* The default part parser is {@link OpenApiParser} which allows for schema-driven marshalling.
*
*
Example:
*
* // Create a client that uses UON format by default for incoming HTTP parts.
* RestClient client = RestClient
* .create ()
* .partParser(UonParser.class )
* .build();
*
*
* @param value
* The new value for this setting.
*
The default value is {@link OpenApiParser}.
* @return This object.
*/
@FluentSetter
public Builder partParser(Class extends HttpPartParser> value) {
partParser().type(value);
return this;
}
/**
* Part parser.
*
*
* The parser to use for parsing POJOs from form data, query parameters, headers, and path variables.
*
*
* The default part parser is {@link OpenApiParser} which allows for schema-driven marshalling.
*
*
Example:
*
* // Create a client that uses UON format by default for incoming HTTP parts.
* RestClient client = RestClient
* .create ()
* .partParser(UonParser.DEFAULT )
* .build();
*
*
* @param value
* The new value for this setting.
*
The default value is {@link OpenApiParser}.
* @return This object.
*/
@FluentSetter
public Builder partParser(HttpPartParser value) {
partParser().impl(value);
return this;
}
//------------------------------------------------------------------------------------------------------------------
// urlEncodingSerializer
//------------------------------------------------------------------------------------------------------------------
/**
* Returns the URL-encoding serializer sub-builder.
*
* @return The URL-encoding serializer sub-builder.
*/
public final UrlEncodingSerializer.Builder urlEncodingSerializer() {
if (urlEncodingSerializer == null)
urlEncodingSerializer = createUrlEncodingSerializer();
return urlEncodingSerializer;
}
/**
* Instantiates the URL-encoding serializer sub-builder.
*
* @return A new URL-encoding serializer sub-builder.
*/
protected UrlEncodingSerializer.Builder createUrlEncodingSerializer() {
return UrlEncodingSerializer.create().beanContext(beanContext());
}
//------------------------------------------------------------------------------------------------------------------
// headerData
//------------------------------------------------------------------------------------------------------------------
/**
* Returns the builder for the list of headers that get applied to all requests created by this builder.
*
*
* This is the primary method for accessing the request header list.
* On first call, the builder is created via the method {@link #createHeaderData()}.
*
*
Example:
*
* // Create a client that adds a "Foo: bar" header on every request.
* RestClient.Builder builder = RestClient.create ();
* builder .headerData().setDefault("Foo" , "bar" ));
* RestClient client = builder .build();
*
*
*
* The following convenience methods are also provided for updating the headers:
*
* - {@link #headers(Header...)}
*
- {@link #headersDefault(Header...)}
*
- {@link #header(String,String)}
*
- {@link #header(String,Supplier)}
*
- {@link #mediaType(String)}
*
- {@link #mediaType(MediaType)}
*
- {@link #accept(String)}
*
- {@link #acceptCharset(String)}
*
- {@link #clientVersion(String)}
*
- {@link #contentType(String)}
*
- {@link #debug()}
*
- {@link #noTrace()}
*
*
* @return The header list builder.
*/
public final HeaderList headers() {
if (headerData == null)
headerData = createHeaderData();
return headerData;
}
/**
* Creates the builder for the header list.
*
*
* Subclasses can override this method to provide their own implementation.
*
*
* The default behavior creates an empty builder.
*
* @return The header list builder.
* @see #headers()
*/
protected HeaderList createHeaderData() {
return HeaderList.create();
}
/**
* Appends multiple headers to all requests.
*
*
Example:
*
* import static org.apache.juneau.http.HttpHeaders.*;
*
* RestClient client = RestClient
* .create ()
* .headers(
* ACCEPT_TEXT_XML ,
* stringHeader ("Foo" , "bar" )
* )
* .build();
*
*
*
* This is a shortcut for calling headerData().append(parts ) .
*
* @param parts
* The header to set.
* @return This object.
* @see #headers()
*/
@FluentSetter
public Builder headers(Header...parts) {
headers().append(parts);
return this;
}
/**
* Sets default header values.
*
*
* Uses default values for specified headers if not otherwise specified on the outgoing requests.
*
*
Example:
*
* RestClient client = RestClient
* .create ()
* .headersDefault(stringHeader ("Foo" , ()->"bar" ));
* .build();
*
*
*
* This is a shortcut for calling headerData().setDefault(parts ) .
*
* @param parts The header values.
* @return This object.
* @see #headers()
*/
public Builder headersDefault(Header...parts) {
headers().setDefault(parts);
return this;
}
/**
* Appends a header to all requests.
*
*
Example:
*
* RestClient client = RestClient
* .create ()
* .header("Foo" , "bar" );
* .build();
*
*
*
* This is a shortcut for calling headerData().append(name ,value ) .
*
* @param name The header name.
* @param value The header value.
* @return This object.
* @see #headers()
*/
@FluentSetter
public Builder header(String name, String value) {
headers().append(name, value);
return this;
}
/**
* Appends a header to all requests using a dynamic value.
*
*
Example:
*
* RestClient client = RestClient
* .create ()
* .header("Foo" , ()->"bar" );
* .build();
*
*
*
* This is a shortcut for calling headerData().append(name ,value ) .
*
* @param name The header name.
* @param value The header value supplier.
* @return This object.
* @see #headers()
*/
@FluentSetter
public Builder header(String name, Supplier value) {
headers().append(name, value);
return this;
}
/**
* Appends the Accept and Content-Type headers on all requests made by this client.
*
*
* Headers are appended to the end of the current header list.
*
*
* This is a shortcut for calling headerData().append(Accept.of (value ), ContentType.of (value )) .
*
* @param value The new header values.
* @return This object.
* @see #headers()
*/
@FluentSetter
public Builder mediaType(String value) {
super.mediaType(MediaType.of(value));
return headers(Accept.of(value), ContentType.of(value));
}
/**
* Appends the Accept and Content-Type headers on all requests made by this client.
*
*
* Headers are appended to the end of the current header list.
*
*
* This is a shortcut for calling headerData().append(Accept.of (value ), ContentType.of (value )) .
*
* @param value The new header values.
* @return This object.
* @see #headers()
*/
@Override
@FluentSetter
public Builder mediaType(MediaType value) {
super.mediaType(value);
return headers(Accept.of(value), ContentType.of(value));
}
/**
* Appends an Accept header on this request.
*
*
* This is a shortcut for calling headerData().append(Accept.of (value )) .
*
* @param value
* The new header value.
* @return This object.
* @see #headers()
*/
@FluentSetter
public Builder accept(String value) {
return headers(Accept.of(value));
}
/**
* Sets the value for the Accept-Charset request header on all requests.
*
*
* This is a shortcut for calling headerData().append(AcceptCharset.of (value )) .
*
* @param value The new header value.
* @return This object.
* @see #headers()
*/
@FluentSetter
public Builder acceptCharset(String value) {
return headers(AcceptCharset.of(value));
}
/**
* Sets the client version by setting the value for the "Client-Version" header.
*
*
* This is a shortcut for calling headerData().append(ClientVersion.of (value )) .
*
* @param value The version string (e.g. "1.2.3" )
* @return This object.
* @see #headers()
*/
@FluentSetter
public Builder clientVersion(String value) {
return headers(ClientVersion.of(value));
}
/**
* Sets the value for the Content-Type request header on all requests.
*
*
* This is a shortcut for calling headerData().append(ContentType.of (value )) .
*
*
* This overrides the media type specified on the serializer.
*
* @param value The new header value.
* @return This object.
* @see #headers()
*/
@FluentSetter
public Builder contentType(String value) {
return headers(ContentType.of(value));
}
/**
* Sets the value for the Debug request header on all requests.
*
*
* This is a shortcut for calling headerData().append(Debug.of (value )) .
*
* @return This object.
* @see #headers()
*/
@Override
@FluentSetter
public Builder debug() {
super.debug();
serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::debug);
return headers(Debug.TRUE);
}
/**
* When called, No-Trace: true is added to requests.
*
*
* This gives the opportunity for the servlet to not log errors on invalid requests.
* This is useful for testing purposes when you don't want your log file to show lots of errors that are simply the
* results of testing.
*
*
* It's up to the server to decide whether to allow for this.
* The BasicTestRestLogger class watches for this header and prevents logging of status 400+ responses to
* prevent needless logging of test scenarios.
*
* @return This object.
* @see #headers()
*/
@FluentSetter
public Builder noTrace() {
return headers(NoTrace.of(true));
}
//------------------------------------------------------------------------------------------------------------------
// queryData
//------------------------------------------------------------------------------------------------------------------
/**
* Returns the builder for the list of query parameters that get applied to all requests created by this builder.
*
*
* This is the primary method for accessing the query parameter list.
* On first call, the builder is created via the method {@link #createQueryData()}.
*
*
Example:
*
* // Create a client that adds a "foo=bar" query parameter on every request.
* RestClient.Builder builder = RestClient.create ();
* builder .queryData().setDefault("foo" , "bar" ));
* RestClient client = builder .build();
*
*
*
* The following convenience methods are also provided for updating the parameters:
*
* - {@link #queryData(NameValuePair...)}
*
- {@link #queryDataDefault(NameValuePair...)}
*
- {@link #queryData(String,String)}
*
- {@link #queryData(String,Supplier)}
*
*
* @return The query data list builder.
*/
public final PartList queryData() {
if (queryData == null)
queryData = createQueryData();
return queryData;
}
/**
* Creates the builder for the query data list.
*
*
* Subclasses can override this method to provide their own implementation.
*
*
* The default behavior creates an empty builder.
*
* @return The query data list builder.
* @see #queryData()
*/
protected PartList createQueryData() {
return PartList.create();
}
/**
* Appends multiple query parameters to the URI of all requests.
*
*
Example:
*
* import static org.apache.juneau.http.HttpParts.*;
*
* RestClient client = RestClient
* .create ()
* .queryData(
* stringPart ("foo" , "bar" ),
* booleanPart ("baz" , true )
* )
* .build();
*
*
*
* This is a shortcut for calling queryData().append(parts ) .
*
* @param parts
* The query parameters.
* @return This object.
* @see #queryData()
*/
@FluentSetter
public Builder queryData(NameValuePair...parts) {
queryData().append(parts);
return this;
}
/**
* Sets default query parameter values.
*
*
* Uses default values for specified parameters if not otherwise specified on the outgoing requests.
*
*
Example:
*
* RestClient client = RestClient
* .create ()
* .queryDataDefault(stringPart ("foo" , ()->"bar" ));
* .build();
*
*
*
* This is a shortcut for calling queryData().setDefault(parts ) .
*
* @param parts The parts.
* @return This object.
* @see #queryData()
*/
public Builder queryDataDefault(NameValuePair...parts) {
queryData().setDefault(parts);
return this;
}
/**
* Appends a query parameter to the URI.
*
*
Example:
*
* RestClient client = RestClient
* .create ()
* .queryData("foo" , "bar" )
* .build();
*
*
*
* This is a shortcut for calling queryData().append(name ,value ) .
*
* @param name The parameter name.
* @param value The parameter value.
* @return This object.
* @see #queryData()
*/
@FluentSetter
public Builder queryData(String name, String value) {
queryData().append(name, value);
return this;
}
/**
* Appends a query parameter with a dynamic value to the URI.
*
*
Example:
*
* RestClient client = RestClient
* .create ()
* .queryData("foo" , ()->"bar" )
* .build();
*
*
*
* This is a shortcut for calling queryData().append(name ,value ) .
*
* @param name The parameter name.
* @param value The parameter value supplier.
* @return This object.
* @see #queryData()
*/
@FluentSetter
public Builder queryData(String name, Supplier value) {
queryData().append(name, value);
return this;
}
//------------------------------------------------------------------------------------------------------------------
// formData
//------------------------------------------------------------------------------------------------------------------
/**
* Returns the builder for the list of form data parameters that get applied to all requests created by this builder.
*
*
* This is the primary method for accessing the form data parameter list.
* On first call, the builder is created via the method {@link #createFormData()}.
*
*
Example:
*
* // Create a client that adds a "foo=bar" form-data parameter on every request.
* RestClient.Builder builder = RestClient.create ();
* builder .formData().setDefault("foo" , "bar" ));
* RestClient client = builder .build();
*
*
*
* The following convenience methods are also provided for updating the parameters:
*
* - {@link #formData(NameValuePair...)}
*
- {@link #formDataDefault(NameValuePair...)}
*
- {@link #formData(String,String)}
*
- {@link #formData(String,Supplier)}
*
*
* @return The form data list builder.
*/
public final PartList formData() {
if (formData == null)
formData = createFormData();
return formData;
}
/**
* Creates the builder for the form data list.
*
*
* Subclasses can override this method to provide their own implementation.
*
*
* The default behavior creates an empty builder.
*
* @return The query data list builder.
* @see #formData()
*/
protected PartList createFormData() {
return PartList.create();
}
/**
* Appends multiple form-data parameters to the request bodies of all URL-encoded form posts.
*
*
Example:
*
* import static org.apache.juneau.http.HttpParts.*;
*
* RestClient client = RestClient
* .create ()
* .formData(
* stringPart ("foo" , "bar" ),
* booleanPart ("baz" , true )
* )
* .build();
*
*
*
* This is a shortcut for calling formData().append(parts ) .
*
* @param parts
* The form-data parameters.
* @return This object.
* @see #formData()
*/
@FluentSetter
public Builder formData(NameValuePair...parts) {
formData().append(parts);
return this;
}
/**
* Sets default form-data parameter values.
*
*
* Uses default values for specified parameters if not otherwise specified on the outgoing requests.
*
*
Example:
*
* RestClient client = RestClient
* .create ()
* .formDataDefault(stringPart ("foo" , ()->"bar" ));
* .build();
*
*
*
* This is a shortcut for calling formData().setDefault(parts ) .
*
* @param parts The parts.
* @return This object.
* @see #formData()
*/
public Builder formDataDefault(NameValuePair...parts) {
formData().setDefault(parts);
return this;
}
/**
* Appends a form-data parameter to all request bodies.
*
*
Example:
*
* RestClient client = RestClient
* .create ()
* .formData("foo" , "bar" )
* .build();
*
*
*
* This is a shortcut for calling formData().append(name ,value ) .
*
* @param name The parameter name.
* @param value The parameter value.
* @return This object.
* @see #formData()
*/
@FluentSetter
public Builder formData(String name, String value) {
formData().append(name, value);
return this;
}
/**
* Appends a form-data parameter with a dynamic value to all request bodies.
*
*
Example:
*
* RestClient client = RestClient
* .create ()
* .formData("foo" , ()->"bar" )
* .build();
*
*
*
* This is a shortcut for calling formData().append(name ,value ) .
*
* @param name The parameter name.
* @param value The parameter value supplier.
* @return This object.
* @see #formData()
*/
@FluentSetter
public Builder formData(String name, Supplier value) {
formData().append(name, value);
return this;
}
//------------------------------------------------------------------------------------------------------------------
// pathData
//------------------------------------------------------------------------------------------------------------------
/**
* Returns the builder for the list of path data parameters that get applied to all requests created by this builder.
*
*
* This is the primary method for accessing the path data parameter list.
* On first call, the builder is created via the method {@link #createFormData()}.
*
*
Example:
*
* // Create a client that uses "bar" for the "{foo}" path variable on every request.
* RestClient.Builder builder = RestClient.create ();
* builder .pathData().setDefault("foo" , "bar" ));
* RestClient client = builder .build();
*
*
*
* The following convenience methods are also provided for updating the parameters:
*
* - {@link #pathData(NameValuePair...)}
*
- {@link #pathDataDefault(NameValuePair...)}
*
- {@link #pathData(String,String)}
*
- {@link #pathData(String,Supplier)}
*
*
* @return The form data list builder.
*/
public final PartList pathData() {
if (pathData == null)
pathData = createPathData();
return pathData;
}
/**
* Creates the builder for the path data list.
*
*
* Subclasses can override this method to provide their own implementation.
*
*
* The default behavior creates an empty builder.
*
* @return The query data list builder.
* @see #pathData()
*/
protected PartList createPathData() {
return PartList.create();
}
/**
* Sets multiple path parameters on all requests.
*
*
Example:
*
* import static org.apache.juneau.http.HttpParts.*;
*
* RestClient client = RestClient
* .create ()
* .pathData(
* stringPart ("foo" , "bar" ),
* booleanPart ("baz" , true )
* )
* .build();
*
*
*
* This is a shortcut for calling pathData().append(parts ) .
*
* @param parts
* The path parameters.
* @return This object.
* @see #pathData()
*/
@FluentSetter
public Builder pathData(NameValuePair...parts) {
pathData().append(parts);
return this;
}
/**
* Sets default path parameter values.
*
*
* Uses default values for specified parameters if not otherwise specified on the outgoing requests.
*
*
Example:
*
* RestClient client = RestClient
* .create ()
* .pathDataDefault(stringPart ("foo" , ()->"bar" ));
* .build();
*
*
*
* This is a shortcut for calling pathData().setDefault(parts ) .
*
* @param parts The parts.
* @return This object.
* @see #pathData()
*/
public Builder pathDataDefault(NameValuePair...parts) {
pathData().setDefault(parts);
return this;
}
/**
* Appends a path parameter to all request bodies.
*
*
Example:
*
* RestClient client = RestClient
* .create ()
* .pathData("foo" , "bar" )
* .build();
*
*
*
* This is a shortcut for calling pathData().append(name ,value ) .
*
* @param name The parameter name.
* @param value The parameter value.
* @return This object.
* @see #pathData()
*/
@FluentSetter
public Builder pathData(String name, String value) {
pathData().append(name, value);
return this;
}
/**
* Sets a path parameter with a dynamic value to all request bodies.
*
*
Example:
*
* RestClient client = RestClient
* .create ()
* .pathData("foo" , ()->"bar" )
* .build();
*
*
*
* This is a shortcut for calling pathData().append(name ,value ) .
*
* @param name The parameter name.
* @param value The parameter value supplier.
* @return This object.
* @see #pathData()
*/
@FluentSetter
public Builder pathData(String name, Supplier value) {
pathData().set(name, value);
return this;
}
//------------------------------------------------------------------------------------------------------------------
// callHandler
//------------------------------------------------------------------------------------------------------------------
/**
* Returns the creator for the rest call handler.
*
*
* Allows you to provide a custom handler for making HTTP calls.
*
*
Example:
*
* // Create a client that handles processing of requests using a custom handler.
* public class MyRestCallHandler implements RestCallHandler {
*
* @Override
* public HttpResponse run(HttpHost target , HttpRequest request , HttpContext context ) throws IOException {
* // Custom handle requests.
* }
* }
*
* RestClient client = RestClient
* .create ()
* .callHandler(MyRestCallHandler.class )
* .build();
*
*
* Notes:
* -
* The {@link RestClient#run(HttpHost, HttpRequest, HttpContext)} method can also be overridden to produce the same results.
*
-
* Use {@link BeanCreator#impl(Object)} to specify an already instantiated instance.
*
-
* Use {@link BeanCreator#type(Class)} to specify a subtype to instantiate.
*
Subclass must have a public constructor that takes in any args available
* in the bean store of this builder (including {@link RestClient} itself).
*
*
* See Also:
* - {@link RestCallHandler}
*
*
* @return The creator for the rest call handler.
*/
public final BeanCreator callHandler() {
if (callHandler == null)
callHandler = createCallHandler();
return callHandler;
}
/**
* Creates the creator for the rest call handler.
*
*
* Subclasses can override this method to provide their own implementation.
*
*
* The default behavior creates a bean creator initialized to return a {@link BasicRestCallHandler}.
*
* @return The creator for the rest call handler.
* @see #callHandler()
*/
protected BeanCreator createCallHandler() {
return beanStore.createBean(RestCallHandler.class).type(BasicRestCallHandler.class);
}
/**
* REST call handler class.
*
*
* Specifies a custom handler for making HTTP calls.
*
*
* This is a shortcut for callHandler().type(value ) .
*
* @param value
* The new value for this setting.
* @return This object.
* @see #callHandler()
*/
@FluentSetter
public Builder callHandler(Class extends RestCallHandler> value) {
callHandler().type(value);
return this;
}
//------------------------------------------------------------------------------------------------------------------
// errorCodes
//------------------------------------------------------------------------------------------------------------------
/**
* Errors codes predicate.
*
*
* Defines a predicate to test for error codes.
*
*
Example:
*
* // Create a client that considers any 300+ responses to be errors.
* RestClient client = RestClient
* .create ()
* .errorCodes(x -> x >=300)
* .build();
*
*
* @param value
* The new value for this setting.
*
The default value is x -> x >= 400
.
* @return This object.
*/
@FluentSetter
public Builder errorCodes(Predicate value) {
errorCodes = assertArgNotNull("value", value);
return this;
}
//------------------------------------------------------------------------------------------------------------------
// Logging.
//------------------------------------------------------------------------------------------------------------------
/**
* Logger.
*
*
* Specifies the logger to use for logging.
*
*
* If not specified, uses the following logger:
*
* Logger.getLogger (RestClient.class .getName());
*
*
* Example:
*
* // Construct a client that logs messages to a special logger.
* RestClient client = RestClient
* .create ()
* .logger(Logger.getLogger ("MyLogger" )) // Log to MyLogger logger.
* .logToConsole() // Also log to console.
* .logRequests(FULL , WARNING ) // Log requests with full detail at WARNING level.
* .build();
*
*
* @param value The logger to use for logging.
* @return This object.
*/
@FluentSetter
public Builder logger(Logger value) {
logger = value;
return this;
}
/**
* Log to console.
*
*
* Specifies to log messages to the console.
*
*
Example:
*
* // Construct a client that logs messages to a special logger.
* RestClient client = RestClient
* .create ()
* .logToConsole()
* .logRequests(FULL , INFO ) // Level is ignored when logging to console.
* .build();
*
*
* @return This object.
*/
@FluentSetter
public Builder logToConsole() {
logToConsole = true;
return this;
}
/**
* Log requests.
*
*
* Causes requests/responses to be logged at the specified log level at the end of the request.
*
*
* SIMPLE detail produces a log message like the following:
*
* POST http://localhost:10000/testUrl, HTTP/1.1 200 OK
*
*
*
* FULL detail produces a log message like the following:
*
* === HTTP Call (outgoing) =======================================================
* === REQUEST ===
* POST http://localhost:10000/testUrl
* ---request headers---
* Debug: true
* No-Trace: true
* Accept: application/json
* ---request entity---
* Content-Type: application/json
* ---request content---
* {"foo":"bar","baz":123}
* === RESPONSE ===
* HTTP/1.1 200 OK
* ---response headers---
* Content-Type: application/json;charset=utf-8
* Content-Length: 21
* Server: Jetty(8.1.0.v20120127)
* ---response content---
* {"message":"OK then"}
* === END ========================================================================
*
*
*
* By default, the message is logged to the default logger. It can be logged to a different logger via the
* {@link #logger(Logger)} method or logged to the console using the
* {@link #logToConsole()} method.
*
* @param detail The detail level of logging.
* @param level The log level.
* @param test A predicate to use per-request to see if the request should be logged. If null , always logs.
* @return This object.
*/
@FluentSetter
public Builder logRequests(DetailLevel detail, Level level, BiPredicate test) {
logRequests = detail;
logRequestsLevel = level;
logRequestsPredicate = test;
return this;
}
//------------------------------------------------------------------------------------------------------------------
// HttpClientConnectionManager methods.
//------------------------------------------------------------------------------------------------------------------
/**
* Creates the {@link HttpClientConnectionManager} returned by {@link #createConnectionManager()}.
*
*
* Subclasses can override this method to provide their own connection manager.
*
*
* The default implementation returns an instance of a {@link PoolingHttpClientConnectionManager} if {@link #pooled()}
* was called or {@link BasicHttpClientConnectionManager} if not..
*
*
Example:
*
* // A Builder that provides it's own customized HttpClientConnectionManager.
* public class MyBuilder extends Builder {
* @Override
* protected HttpClientConnectionManager createConnectionManager() {
* return new PoolingHttpClientConnectionManager();
* }
* }
*
* // Instantiate.
* RestClient client = new MyBuilder().build();
*
*
* @return The HTTP client builder to use to create the HTTP client.
*/
protected HttpClientConnectionManager createConnectionManager() {
return (pooled ? new PoolingHttpClientConnectionManager() : new BasicHttpClientConnectionManager());
}
/**
* When called, the {@link #createConnectionManager()} method will return a {@link PoolingHttpClientConnectionManager}
* instead of a {@link BasicHttpClientConnectionManager}.
*
* Example:
*
* // Construct a client that uses pooled connections.
* RestClient client = RestClient
* .create ()
* .pooled()
* .build();
*
*
* @return This object.
*/
@FluentSetter
public Builder pooled() {
this.pooled = true;
return this;
}
/**
* Assigns {@link HttpClientConnectionManager} instance.
*
* @param value New property value.
* @return This object.
* @see HttpClientBuilder#setConnectionManager(HttpClientConnectionManager)
*/
@FluentSetter
public Builder connectionManager(HttpClientConnectionManager value) {
connectionManager = value;
httpClientBuilder().setConnectionManager(value);
return this;
}
/**
* Defines the connection manager is to be shared by multiple client instances.
*
* Notes:
* - If the connection manager is shared its life-cycle is expected to be managed by the caller and it will not be shut down if the client is closed.
*
*
* @param shared New property value.
* @return This object.
* @see HttpClientBuilder#setConnectionManagerShared(boolean)
*/
@FluentSetter
public Builder connectionManagerShared(boolean shared) {
httpClientBuilder().setConnectionManagerShared(shared);
return this;
}
/**
* Set up this client to use BASIC auth.
*
* Example:
*
* // Construct a client that uses BASIC authentication.
* RestClient client = RestClient
* .create ()
* .basicAuth("http://localhost" , 80, "me" , "mypassword" )
* .build();
*
*
* @param host The auth scope hostname.
* @param port The auth scope port.
* @param user The username.
* @param pw The password.
* @return This object.
*/
@FluentSetter
public Builder basicAuth(String host, int port, String user, String pw) {
AuthScope scope = new AuthScope(host, port);
Credentials up = new UsernamePasswordCredentials(user, pw);
CredentialsProvider p = new BasicCredentialsProvider();
p.setCredentials(scope, up);
defaultCredentialsProvider(p);
return this;
}
//-----------------------------------------------------------------------------------------------------------------
// Properties
//-----------------------------------------------------------------------------------------------------------------
/**
* Console print stream
*
*
* Allows you to redirect the console output to a different print stream.
*
* @param value
* The new value for this setting.
* @return This object.
*/
@FluentSetter
public Builder console(PrintStream value) {
console = value;
return this;
}
/**
* RestClient configuration property: Executor service.
*
*
* Defines the executor service to use when calling future methods on the {@link RestRequest} class.
*
*
* This executor service is used to create {@link Future} objects on the following methods:
*
* - {@link RestRequest#runFuture()}
*
- {@link RestRequest#completeFuture()}
*
- {@link ResponseContent#asFuture(Class)} (and similar methods)
*
*
*
* The default executor service is a single-threaded {@link ThreadPoolExecutor} with a 30 second timeout
* and a queue size of 10.
*
*
Example:
*
* // Create a client with a customized executor service.
* RestClient client = RestClient
* .create ()
* .executorService(new ThreadPoolExecutor(1, 1, 30, TimeUnit.SECONDS , new ArrayBlockingQueue<Runnable>(10)), true )
* .build();
*
* // Use it to asynchronously run a request.
* Future<RestResponse> responseFuture = client .get(URI ).runFuture();
*
* // Do some other stuff.
*
* // Now read the response.
* String body = responseFuture .get().getContent().asString();
*
* // Use it to asynchronously retrieve a response.
* Future<MyBean> myBeanFuture = client
* .get(URI )
* .run()
* .getContent().asFuture(MyBean.class );
*
* // Do some other stuff.
*
* // Now read the response.
* MyBean bean = myBeanFuture .get();
*
*
* @param executorService The executor service.
* @param shutdownOnClose Call {@link ExecutorService#shutdown()} when {@link RestClient#close()} is called.
* @return This object.
*/
@FluentSetter
public Builder executorService(ExecutorService executorService, boolean shutdownOnClose) {
this.executorService = executorService;
this.executorServiceShutdownOnClose = shutdownOnClose;
return this;
}
/**
* RestClient configuration property: Keep HttpClient open.
*
*
* Don't close this client when the {@link RestClient#close()} method is called.
*
*
Example:
*
* // Create a client with a customized client and don't close the client service.
* RestClient client = RestClient
* .create ()
* .httpClient(myHttpClient )
* .keepHttpClientOpen()
* .build();
*
* client .closeQuietly(); // Customized HttpClient won't be closed.
*
*
* @return This object.
*/
@FluentSetter
public Builder keepHttpClientOpen() {
keepHttpClientOpen = true;
return this;
}
/**
* Ignore errors.
*
*
* When enabled, HTTP error response codes (e.g. >=400 ) will not cause a {@link RestCallException} to
* be thrown.
*
* Note that this is equivalent to builder.errorCodes(x -> false );
*
*
Example:
*
* // Create a client that doesn't throws a RestCallException when a 500 error occurs.
* RestClient
* .create ()
* .ignoreErrors()
* .build()
* .get("/error" ) // Throws a 500 error
* .run()
* .assertStatus().is(500);
*
*
* @return This object.
*/
@FluentSetter
public Builder ignoreErrors() {
ignoreErrors = true;
return this;
}
/**
* RestClient configuration property: Call interceptors.
*
*
* Adds an interceptor that can be called to hook into specified events in the lifecycle of a single request.
*
*
Example:
*
* // Customized interceptor (note you can also extend from BasicRestCallInterceptor as well.
* public class MyRestCallInterceptor implements RestCallInterceptor {
*
* @Override
* public void onInit(RestRequest req ) throws Exception {
* // Intercept immediately after RestRequest object is created and all headers/query/form-data has been
* // set on the request from the client.
* }
*
* @Override
* public void onConnect(RestRequest req , RestResponse res ) throws Exception {
* // Intercept immediately after an HTTP response has been received.
* }
*
* @Override
* public void onClose(RestRequest req , RestResponse res ) throws Exception {
* // Intercept when the response body is consumed.
* }
* }
*
* // Create a client with a customized interceptor.
* RestClient client = RestClient
* .create ()
* .interceptors(MyRestCallInterceptor.class )
* .build();
*
*
* Notes:
* - The {@link RestClient#onCallInit(RestRequest)}, {@link RestClient#onCallConnect(RestRequest,RestResponse)}, and
* {@link RestClient#onCallClose(RestRequest,RestResponse)} methods can also be overridden to produce the same results.
*
*
* @param values
* The values to add to this setting.
*
Can be implementations of any of the following:
*
* - {@link RestCallInterceptor}
*
- {@link HttpRequestInterceptor}
*
- {@link HttpResponseInterceptor}
*
* @return This object.
* @throws Exception If one or more interceptors could not be created.
*/
@FluentSetter
public Builder interceptors(Class>...values) throws Exception {
for (Class> c : values) {
ClassInfo ci = ClassInfo.of(c);
if (ci != null) {
if (ci.isChildOfAny(RestCallInterceptor.class, HttpRequestInterceptor.class, HttpResponseInterceptor.class))
interceptors(ci.newInstance());
else
throw new ConfigException("Invalid class of type ''{0}'' passed to interceptors().", ci.getName());
}
}
return this;
}
/**
* Call interceptors.
*
*
* Adds an interceptor that gets called immediately after a connection is made.
*
*
Example:
*
* // Create a client with a customized interceptor.
* RestClient client = RestClient
* .create ()
* .interceptors(
* new RestCallInterceptor() {
*
* @Override
* public void onInit(RestRequest req ) throws Exception {
* // Intercept immediately after RestRequest object is created and all headers/query/form-data has been
* // set on the request from the client.
* }
*
* @Override
* public void onConnect(RestRequest req , RestResponse res ) throws Exception {
* // Intercept immediately after an HTTP response has been received.
* }
*
* @Override
* public void onClose(RestRequest req , RestResponse res ) throws Exception {
* // Intercept when the response body is consumed.
* }
* }
* )
* .build();
*
*
* Notes:
* - The {@link RestClient#onCallInit(RestRequest)}, {@link RestClient#onCallConnect(RestRequest,RestResponse)}, and
* {@link RestClient#onCallClose(RestRequest,RestResponse)} methods can also be overridden to produce the same results.
*
*
* @param value
* The values to add to this setting.
*
Can be implementations of any of the following:
*
* - {@link RestCallInterceptor}
*
- {@link HttpRequestInterceptor}
*
- {@link HttpResponseInterceptor}
*
* @return This object.
*/
@FluentSetter
public Builder interceptors(Object...value) {
List l = list();
for (Object o : value) {
ClassInfo ci = ClassInfo.of(o);
if (ci != null) {
if (! ci.isChildOfAny(HttpRequestInterceptor.class, HttpResponseInterceptor.class, RestCallInterceptor.class))
throw new ConfigException("Invalid object of type ''{0}'' passed to interceptors().", ci.getName());
if (o instanceof HttpRequestInterceptor)
addInterceptorLast((HttpRequestInterceptor)o);
if (o instanceof HttpResponseInterceptor)
addInterceptorLast((HttpResponseInterceptor)o);
if (o instanceof RestCallInterceptor)
l.add((RestCallInterceptor)o);
}
}
if (interceptors == null)
interceptors = l;
else
interceptors.addAll(0, l);
return this;
}
/**
* RestClient configuration property: Enable leak detection.
*
*
* Enable client and request/response leak detection.
*
*
* Causes messages to be logged to the console if clients or request/response objects are not properly closed
* when the finalize methods are invoked.
*
*
* Automatically enabled with {@link org.apache.juneau.Context.Builder#debug()}.
*
*
Example:
*
* // Create a client that logs a message if
* RestClient client = RestClient
* .create ()
* .detectLeaks()
* .logToConsole() // Also log the error message to System.err
* .build();
*
* client .closeQuietly(); // Customized HttpClient won't be closed.
*
*
* @return This object.
*/
@FluentSetter
public Builder detectLeaks() {
detectLeaks = true;
return this;
}
/**
* RestClient configuration property: Marshaller
*
*
* Shortcut for specifying the serializers and parsers
* using the serializer and parser defined in a marshaller.
*
*
Notes:
* - When using this method that takes in a pre-instantiated serializers and parsers, the serializer property setters (e.g. {@link #sortCollections()}),
* parser property setters (e.g. {@link #strict()}), or bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class have no effect.
*
*
* Example:
*
* // Create a client that uses Simplified-JSON transport using an existing marshaller.
* RestClient client = RestClient
* .create ()
* .marshaller(Json5.DEFAULT_READABLE )
* .build();
*
*
* @param value The values to add to this setting.
* @return This object.
*/
@FluentSetter
public Builder marshaller(Marshaller value) {
if (value != null)
serializer(value.getSerializer()).parser(value.getParser());
return this;
}
/**
* RestClient configuration property: Marshalls
*
*
* Shortcut for specifying the serializers and parsers
* using the serializer and parser defined in a marshaller.
*
*
Notes:
* - When using this method that takes in a pre-instantiated serializers and parsers, the serializer property setters (e.g. {@link #sortCollections()}),
* parser property setters (e.g. {@link #strict()}), or bean context property setters (e.g. {@link #swaps(Class...)}) defined on this builder class have no effect.
*
*
* Example:
*
* // Create a client that uses JSON and XML transport using existing marshalls.
* RestClient client = RestClient
* .create ()
* .marshaller(Json.DEFAULT_READABLE , Xml.DEFAULT_READABLE )
* .build();
*
*
* @param value The values to add to this setting.
* @return This object.
*/
@FluentSetter
public Builder marshallers(Marshaller...value) {
for (Marshaller m : value)
if (m != null)
serializer(m.getSerializer()).parser(m.getParser());
return this;
}
/**
* RestClient configuration property: Root URI.
*
*
* When set, relative URI strings passed in through the various rest call methods (e.g. {@link RestClient#get(Object)}
* will be prefixed with the specified root.
*
This root URI is ignored on those methods if you pass in a {@link URL}, {@link URI}, or an absolute URI string.
*
*
Example:
*
* // Create a client that uses UON format by default for HTTP parts.
* RestClient client = RestClient
* .create ()
* .rootUrl("http://localhost:10000/foo" )
* .build();
*
* Bar bar = client
* .get("/bar" ) // Relative to http://localhost:10000/foo
* .run()
* .getContent().as(Bar.class );
*
*
* @param value
* The root URI to prefix to relative URI strings.
*
Trailing slashes are trimmed.
*
Usually a String but you can also pass in URI and URL objects as well.
* @return This object.
*/
@FluentSetter
public Builder rootUrl(Object value) {
String s = stringify(value);
if (! isEmpty(s))
s = s.replaceAll("\\/$", "");
if (isEmpty(s))
rootUrl = null;
else if (s.indexOf("://") == -1)
throw new BasicRuntimeException("Invalid rootUrl value: ''{0}''. Must be a valid absolute URL.", value);
else
rootUrl = s;
return this;
}
/**
* Returns the root URI defined for this client.
*
*
* Returns null in leu of an empty string.
* Trailing slashes are trimmed.
*
* @return The root URI defined for this client.
*/
public String getRootUri() {
return rootUrl;
}
/**
* Skip empty form data.
*
*
* When enabled, form data consisting of empty strings will be skipped on requests.
* Note that null values are already skipped.
*
*
* The {@link Schema#skipIfEmpty()} annotation overrides this setting.
*
* @param value
* The new value for this setting.
*
The default is false .
* @return This object.
*/
@FluentSetter
public Builder skipEmptyFormData(boolean value) {
skipEmptyFormData = true;
return this;
}
/**
* Skip empty form data.
*
*
* When enabled, form data consisting of empty strings will be skipped on requests.
* Note that null values are already skipped.
*
*
* The {@link Schema#skipIfEmpty()} annotation overrides this setting.
*
* @return This object.
*/
@FluentSetter
public Builder skipEmptyFormData() {
return skipEmptyFormData(true);
}
/**
* Skip empty header data.
*
*
* When enabled, headers consisting of empty strings will be skipped on requests.
* Note that null values are already skipped.
*
*
* The {@link Schema#skipIfEmpty()} annotation overrides this setting.
*
* @param value
* The new value for this setting.
*
The default is false .
* @return This object.
*/
@FluentSetter
public Builder skipEmptyHeaderData(boolean value) {
skipEmptyHeaderData = true;
return this;
}
/**
* Skip empty header data.
*
*
* When enabled, headers consisting of empty strings will be skipped on requests.
* Note that null values are already skipped.
*
*
* The {@link Schema#skipIfEmpty()} annotation overrides this setting.
*
* @return This object.
*/
@FluentSetter
public Builder skipEmptyHeaderData() {
return skipEmptyHeaderData(true);
}
/**
* Skip empty query data.
*
*
* When enabled, query parameters consisting of empty strings will be skipped on requests.
* Note that null values are already skipped.
*
*
* The {@link Schema#skipIfEmpty()} annotation overrides this setting.
*
* @param value
* The new value for this setting.
*
The default is false .
* @return This object.
*/
@FluentSetter
public Builder skipEmptyQueryData(boolean value) {
skipEmptyQueryData = true;
return this;
}
/**
* Skip empty query data.
*
*
* When enabled, query parameters consisting of empty strings will be skipped on requests.
* Note that null values are already skipped.
*
*
* The {@link Schema#skipIfEmpty()} annotation overrides this setting.
*
* @return This object.
*/
@FluentSetter
public Builder skipEmptyQueryData() {
return skipEmptyQueryData(true);
}
//-----------------------------------------------------------------------------------------------------------------
// BeanTraverse Properties
//-----------------------------------------------------------------------------------------------------------------
/**
* BeanTraverse configuration property: Automatically detect POJO recursions.
*
*
* When enabled, specifies that recursions should be checked for during traversal.
*
*
* Recursions can occur when traversing models that aren't true trees but rather contain loops.
*
In general, unchecked recursions cause stack-overflow-errors.
*
These show up as {@link BeanRecursionException BeanRecursionException} with the message "Depth too deep. Stack overflow occurred." .
*
*
Notes:
* -
* Checking for recursion can cause a small performance penalty.
*
*
* Example:
*
* // Create a JSON client that automatically checks for recursions.
* RestClient client = RestClient
* .create ()
* .json()
* .detectRecursions()
* .build();
*
* // Create a POJO model with a recursive loop.
* public class A {
* public Object f ;
* }
* A a = new A();
* a .f = a ;
*
* try {
* // Throws a RestCallException with an inner SerializeException and not a StackOverflowError
* client
* .post("http://localhost:10000/foo" , a )
* .run();
* } catch (RestCallException e } {
* // Handle exception.
* }
*
*
* See Also:
* - {@link org.apache.juneau.BeanTraverseContext.Builder#detectRecursions()}
*
*
* @return This object.
*/
@FluentSetter
public Builder detectRecursions() {
serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::detectRecursions);
return this;
}
/**
* BeanTraverse configuration property: Ignore recursion errors.
*
*
* When enabled, when we encounter the same object when traversing a tree, we set the value to null .
*
*
* For example, if a model contains the links A->B->C->A, then the JSON generated will look like
* the following when BEANTRAVERSE_ignoreRecursions is true ...
*
*
* {A:{B:{C:null }}}
*
*
* Notes:
* -
* Checking for recursion can cause a small performance penalty.
*
*
* Example:
*
* // Create a JSON client that ignores recursions.
* RestClient client = RestClient
* .create ()
* .json()
* .ignoreRecursions()
* .build();
*
* // Create a POJO model with a recursive loop.
* public class A {
* public Object f ;
* }
* A a = new A();
* a .f = a ;
*
* // Produces request body "{f:null}"
* client
* .post("http://localhost:10000/foo" , a )
* .run();
*
*
* See Also:
* - {@link org.apache.juneau.BeanTraverseContext.Builder#ignoreRecursions()}
*
*
* @return This object.
*/
@FluentSetter
public Builder ignoreRecursions() {
serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::ignoreRecursions);
return this;
}
/**
* BeanTraverse configuration property: Initial depth.
*
*
* The initial indentation level at the root.
*
*
* Useful when constructing document fragments that need to be indented at a certain level when whitespace is enabled.
*
*
Example:
*
* // Create a REST client with JSON serializer with whitespace enabled and an initial depth of 2.
* RestClient client = RestClient
* .create ()
* .json()
* .ws()
* .initialDepth(2)
* .build();
*
* // Our bean to serialize.
* public class MyBean {
* public String foo = null ;
* }
*
* // Produces request body "\t\t{\n\t\t\t'foo':'bar'\n\t\t}\n"
* client
* .post("http://localhost:10000/foo" , new MyBean())
* .run();
*
*
* See Also:
* - {@link org.apache.juneau.BeanTraverseContext.Builder#initialDepth(int)}
*
*
* @param value
* The new value for this property.
*
The default is 0 .
* @return This object.
*/
@FluentSetter
public Builder initialDepth(int value) {
serializers().forEach(x -> x.initialDepth(value));
return this;
}
/**
* BeanTraverse configuration property: Max serialization depth.
*
*
* When enabled, abort traversal if specified depth is reached in the POJO tree.
*
*
* If this depth is exceeded, an exception is thrown.
*
*
* This prevents stack overflows from occurring when trying to traverse models with recursive references.
*
*
Example:
*
* // Create a REST client with JSON serializer that throws an exception if the depth reaches greater than 20.
* RestClient client = RestClient
* .create ()
* .json()
* .maxDepth(20)
* .build();
*
*
* See Also:
* - {@link org.apache.juneau.BeanTraverseContext.Builder#maxDepth(int)}
*
*
* @param value
* The new value for this property.
*
The default is 100 .
* @return This object.
*/
@FluentSetter
public Builder maxDepth(int value) {
serializers().forEach(x -> x.maxDepth(value));
return this;
}
//-----------------------------------------------------------------------------------------------------------------
// Serializer Properties
//-----------------------------------------------------------------------------------------------------------------
/**
* Serializer configuration property: Add "_type" properties when needed.
*
*
* When enabled, "_type" properties will be added to beans if their type cannot be inferred
* through reflection.
*
*
* This is used to recreate the correct objects during parsing if the object types cannot be inferred.
*
For example, when serializing a Map<String,Object> field where the bean class cannot be determined from
* the type of the values.
*
*
* Note the differences between the following settings:
*
* - {@link #addRootType()} - Affects whether
'_type' is added to root node.
* - {@link #addBeanTypes()} - Affects whether
'_type' is added to any nodes.
*
*
* Example:
*
* // Create a JSON client that adds _type to nodes in the request body.
* RestClient client = RestClient
* .create ()
* .json()
* .addBeanTypes()
* .build();
*
* // Our map of beans to serialize.
* @Bean (typeName="mybean" )
* public class MyBean {
* public String foo = "bar" ;
* }
*
* AMap map = AMap.of("foo" , new MyBean());
*
* // Request body will contain: {"foo":{"_type":"mybean","foo":"bar"}}
* client
* .post("http://localhost:10000/foo" , map )
* .run();
*
*
* See Also:
* - {@link org.apache.juneau.serializer.Serializer.Builder#addBeanTypes()}
*
*
* @return This object.
*/
@FluentSetter
public Builder addBeanTypes() {
serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::addBeanTypes);
return this;
}
/**
* Serializer configuration property: Add type attribute to root nodes.
*
*
* When enabled, "_type" properties will be added to top-level beans.
*
*
* When disabled, it is assumed that the parser knows the exact Java POJO type being parsed, and therefore top-level
* type information that might normally be included to determine the data type will not be serialized.
*
*
* For example, when serializing a top-level POJO with a {@link Bean#typeName() @Bean(typeName)} value, a
* '_type' attribute will only be added when this setting is enabled.
*
*
* Note the differences between the following settings:
*
* - {@link #addRootType()} - Affects whether
'_type' is added to root node.
* - {@link #addBeanTypes()} - Affects whether
'_type' is added to any nodes.
*
*
* Example:
*
* // Create a JSON client that adds _type to root node.
* RestClient client = RestClient
* .create ()
* .json()
* .addRootType()
* .build();
*
* // Our bean to serialize.
* @Bean (typeName="mybean" )
* public class MyBean {
* public String foo = "bar" ;
* }
*
* // Request body will contain: {"_type":"mybean","foo":"bar"}
* client
* .post("http://localhost:10000/foo" , new MyBean())
* .run();
*
*
* See Also:
* - {@link org.apache.juneau.serializer.Serializer.Builder#addRootType()}
*
*
* @return This object.
*/
@FluentSetter
public Builder addRootType() {
serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::addRootType);
return this;
}
/**
* Serializer configuration property: Don't trim null bean property values.
*
*
* When enabled, null bean values will be serialized to the output.
*
*
Notes:
* - Not enabling this setting will cause
Map s with null values to be lost during parsing.
*
*
* Example:
*
* // Create a REST client with JSON serializer that serializes null properties.
* RestClient client = RestClient
* .create ()
* .json()
* .keepNullProperties()
* .build();
*
* // Our bean to serialize.
* public class MyBean {
* public String foo = null ;
* }
*
* // Request body will contain: {foo:null}
* client
* .post("http://localhost:10000/foo" , new MyBean())
* .run();
*
*
* See Also:
* - {@link org.apache.juneau.serializer.Serializer.Builder#keepNullProperties()}
*
*
* @return This object.
*/
@FluentSetter
public Builder keepNullProperties() {
serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::keepNullProperties);
return this;
}
/**
* Serializer configuration property: Sort arrays and collections alphabetically.
*
*
* When enabled, copies and sorts the contents of arrays and collections before serializing them.
*
*
* Note that this introduces a performance penalty since it requires copying the existing collection.
*
*
Example:
*
* // Create a REST client with JSON serializer that sorts arrays and collections before serialization.
* RestClient client = RestClient
* .create ()
* .json()
* .sortCollections()
* .build();
*
* // An unsorted array
* String[] array = {"foo" ,"bar" ,"baz" }
*
* // Request body will contain: ["bar","baz","foo"]
* client
* .post("http://localhost:10000/foo" , array )
* .run();
*
*
* See Also:
* - {@link org.apache.juneau.serializer.Serializer.Builder#sortCollections()}
*
*
* @return This object.
*/
@FluentSetter
public Builder sortCollections() {
serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::sortCollections);
return this;
}
/**
* Serializer configuration property: Sort maps alphabetically.
*
*
* When enabled, copies and sorts the contents of maps by their keys before serializing them.
*
*
* Note that this introduces a performance penalty.
*
*
Example:
*
* // Create a REST client with JSON serializer that sorts maps before serialization.
* RestClient client = RestClient
* .create ()
* .json()
* .sortMaps()
* .build();
*
* // An unsorted map.
* AMap map = AMap.of ("foo" ,1,"bar" ,2,"baz" ,3);
*
* // Request body will contain: {"bar":2,"baz":3,"foo":1}
* client
* .post("http://localhost:10000/foo" , map )
* .run();
*
*
* See Also:
* - {@link org.apache.juneau.serializer.Serializer.Builder#sortMaps()}
*
*
* @return This object.
*/
@FluentSetter
public Builder sortMaps() {
serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::sortMaps);
return this;
}
/**
* Serializer configuration property: Trim empty lists and arrays.
*
*
* When enabled, empty lists and arrays will not be serialized.
*
*
* Note that enabling this setting has the following effects on parsing:
*
* -
* Map entries with empty list values will be lost.
*
-
* Bean properties with empty list values will not be set.
*
*
* Example:
*
* // Create a serializer that skips empty arrays and collections.
* WriterSerializer serializer = JsonSerializer
* .create ()
* .trimEmptyCollections()
* .build();
*
* // A bean with a field with an empty array.
* public class MyBean {
* public String[] foo = {};
* }
*
* // Request body will contain: {}
* client
* .post("http://localhost:10000/foo" , new MyBean())
* .run();
*
*
* See Also:
* - {@link org.apache.juneau.serializer.Serializer.Builder#trimEmptyCollections()}
*
*
* @return This object.
*/
@FluentSetter
public Builder trimEmptyCollections() {
serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::trimEmptyCollections);
return this;
}
/**
* Serializer configuration property: Trim empty maps.
*
*
* When enabled, empty map values will not be serialized to the output.
*
*
* Note that enabling this setting has the following effects on parsing:
*
* -
* Bean properties with empty map values will not be set.
*
*
* Example:
*
* // Create a REST client with JSON serializer that skips empty maps.
* RestClient client = RestClient
* .create ()
* .json()
* .trimEmptyMaps()
* .build();
*
* // A bean with a field with an empty map.
* public class MyBean {
* public AMap foo = AMap.of ();
* }
*
* // Request body will contain: {}
* client
* .post("http://localhost:10000/foo" , new MyBean())
* .run();
*
*
* See Also:
* - {@link org.apache.juneau.serializer.Serializer.Builder#trimEmptyMaps()}
*
*
* @return This object.
*/
@FluentSetter
public Builder trimEmptyMaps() {
serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::trimEmptyMaps);
return this;
}
/**
* Serializer configuration property: Trim strings.
*
*
* When enabled, string values will be trimmed of whitespace using {@link String#trim()} before being serialized.
*
*
Example:
*
* // Create a REST client with JSON serializer that trims strings before serialization.
* RestClient client = RestClient
* .create ()
* .json()
* .trimStrings()
* .build();
*
* // A map with space-padded keys/values
* AMap map = AMap.of (" foo " , " bar " );
*
* // Request body will contain: {"foo":"bar"}
* client
* .post("http://localhost:10000/foo" , map )
* .run();
*
*
* See Also:
* - {@link org.apache.juneau.serializer.Serializer.Builder#trimStrings()}
*
*
* @return This object.
*/
@FluentSetter
public Builder trimStringsOnWrite() {
serializers().forEach(org.apache.juneau.serializer.Serializer.Builder::trimStrings);
return this;
}
/**
* Serializer configuration property: URI context bean.
*
*
* Bean used for resolution of URIs to absolute or root-relative form.
*
*
Example:
*
* // Our URI contextual information.
* String authority = "http://localhost:10000" ;
* String contextRoot = "/myContext" ;
* String servletPath = "/myServlet" ;
* String pathInfo = "/foo" ;
*
* // Create a UriContext object.
* UriContext uriContext = new UriContext(authority , contextRoot , servletPath , pathInfo );
*
* // Create a REST client with JSON serializer and associate our context.
* RestClient client = RestClient
* .create ()
* .json()
* .uriContext(uriContext )
* .uriRelativity(RESOURCE ) // Assume relative paths are relative to servlet.
* .uriResolution(ABSOLUTE ) // Serialize URIs as absolute paths.
* .build();
*
* // A relative URI
* URI uri = new URI("bar" );
*
* // Request body will contain: "http://localhost:10000/myContext/myServlet/foo/bar"
* client
* .post("http://localhost:10000/foo" , uri )
* .run();
*
*
* See Also:
* - {@link org.apache.juneau.serializer.Serializer.Builder#uriContext(UriContext)}
*
- URIs
*
*
* @param value The new value for this property.
* @return This object.
*/
@FluentSetter
public Builder uriContext(UriContext value) {
serializers().forEach(x -> x.uriContext(value));
return this;
}
/**
* Serializer configuration property: URI relativity.
*
*
* Defines what relative URIs are relative to when serializing any of the following:
*
* - {@link java.net.URI}
*
- {@link java.net.URL}
*
- Properties and classes annotated with {@link Uri @Uri}
*
*
*
* See {@link #uriContext(UriContext)} for examples.
*
*
* - {@link org.apache.juneau.UriRelativity#RESOURCE}
* - Relative URIs should be considered relative to the servlet URI.
*
- {@link org.apache.juneau.UriRelativity#PATH_INFO}
* - Relative URIs should be considered relative to the request URI.
*
*
* See Also:
* - {@link org.apache.juneau.serializer.Serializer.Builder#uriRelativity(UriRelativity)}
*
- URIs
*
*
* @param value
* The new value for this property.
*
The default is {@link UriRelativity#RESOURCE}
* @return This object.
*/
@FluentSetter
public Builder uriRelativity(UriRelativity value) {
serializers().forEach(x -> x.uriRelativity(value));
return this;
}
/**
* Serializer configuration property: URI resolution.
*
*
* Defines the resolution level for URIs when serializing any of the following:
*
* - {@link java.net.URI}
*
- {@link java.net.URL}
*
- Properties and classes annotated with {@link Uri @Uri}
*
*
*
* See {@link #uriContext(UriContext)} for examples.
*
*
* - {@link UriResolution#ABSOLUTE}
* - Resolve to an absolute URI (e.g.
"http://host:port/context-root/servlet-path/path-info" ).
* - {@link UriResolution#ROOT_RELATIVE}
* - Resolve to a root-relative URI (e.g.
"/context-root/servlet-path/path-info" ).
* - {@link UriResolution#NONE}
* - Don't do any URI resolution.
*
*
* See Also:
* - {@link org.apache.juneau.serializer.Serializer.Builder#uriResolution(UriResolution)}
*
- URIs
*
*
* @param value
* The new value for this property.
*
The default is {@link UriResolution#NONE}
* @return This object.
*/
@FluentSetter
public Builder uriResolution(UriResolution value) {
serializers().forEach(x -> x.uriResolution(value));
return this;
}
//-----------------------------------------------------------------------------------------------------------------
// WriterSerializer Properties
//-----------------------------------------------------------------------------------------------------------------
/**
* WriterSerializer configuration property: Maximum indentation.
*
*
* Specifies the maximum indentation level in the serialized document.
*
*
Notes:
* - This setting does not apply to the RDF serializers.
*
*
* Example:
*
* // Create a REST client with JSON serializer that indents a maximum of 20 tabs.
* RestClient client = RestClient
* .create ()
* .json()
* .ws() // Enable whitespace
* .maxIndent(20)
* .build();
*
*
* See Also:
* - {@link org.apache.juneau.serializer.WriterSerializer.Builder#maxIndent(int)}
*
*
* @param value
* The new value for this property.
*
The default is 100 .
* @return This object.
*/
@FluentSetter
public Builder maxIndent(int value) {
serializers().forEachWS(x -> x.maxIndent(value));
return this;
}
/**
* WriterSerializer configuration property: Quote character.
*
*
* Specifies the character to use for quoting attributes and values.
*
*
Notes:
* - This setting does not apply to the RDF serializers.
*
*
* Example:
*
* // Create a REST client with JSON serializer that uses single quotes.
* RestClient client = RestClient
* .create ()
* .json()
* .quoteChar('\'' )
* .build();
*
* // A bean with a single property
* public class MyBean {
* public String foo = "bar" ;
* }
*
* // Request body will contain: {'foo':'bar'}
* client
* .post("http://localhost:10000/foo" , new MyBean())
* .run();
*
*
* See Also:
* - {@link org.apache.juneau.serializer.WriterSerializer.Builder#quoteChar(char)}
*
*
* @param value
* The new value for this property.
*
The default is '"' .
* @return This object.
*/
@FluentSetter
public Builder quoteChar(char value) {
serializers().forEachWS(x -> x.quoteChar(value));
return this;
}
/**
* WriterSerializer configuration property: Quote character.
*
*
* Specifies to use single quotes for quoting attributes and values.
*
*
Notes:
* - This setting does not apply to the RDF serializers.
*
*
* Example:
*
* // Create a REST client with JSON serializer that uses single quotes.
* RestClient client = RestClient
* .create ()
* .json()
* .sq()
* .build();
*
* // A bean with a single property
* public class MyBean {
* public String foo = "bar" ;
* }
*
* // Request body will contain: {'foo':'bar'}
* client
* .post("http://localhost:10000/foo" , new MyBean())
* .run();
*
*
* See Also:
* - {@link org.apache.juneau.serializer.WriterSerializer.Builder#quoteChar(char)}
*
*
* @return This object.
*/
@FluentSetter
public Builder sq() {
serializers().forEachWS(org.apache.juneau.serializer.WriterSerializer.Builder::sq);
return this;
}
/**
* WriterSerializer configuration property: Use whitespace.
*
*
* When enabled, whitespace is added to the output to improve readability.
*
*
Example:
*
* // Create a REST client with JSON serializer with whitespace enabled.
* RestClient client = RestClient
* .create ()
* .json()
* .useWhitespace()
* .build();
*
* // A bean with a single property
* public class MyBean {
* public String foo = "bar" ;
* }
*
* // Request body will contain: {\n\t"foo": "bar"\n\}\n
* client
* .post("http://localhost:10000/foo" , new MyBean())
* .run();
*
*
* See Also:
* - {@link org.apache.juneau.serializer.WriterSerializer.Builder#useWhitespace()}
*
* @return This object.
*/
@FluentSetter
public Builder useWhitespace() {
serializers().forEachWS(org.apache.juneau.serializer.WriterSerializer.Builder::useWhitespace);
return this;
}
/**
* WriterSerializer configuration property: Use whitespace.
*
*
* When enabled, whitespace is added to the output to improve readability.
*
*
Example:
*
* // Create a REST client with JSON serializer with whitespace enabled.
* RestClient client = RestClient
* .create ()
* .json()
* .ws()
* .build();
*
* // A bean with a single property
* public class MyBean {
* public String foo = "bar" ;
* }
*
* // Request body will contain: {\n\t"foo": "bar"\n\}\n
* client
* .post("http://localhost:10000/foo" , new MyBean())
* .run();
*
*
* See Also:
* - {@link org.apache.juneau.serializer.WriterSerializer.Builder#useWhitespace()}
*
*
* @return This object.
*/
@FluentSetter
public Builder ws() {
serializers().forEachWS(org.apache.juneau.serializer.WriterSerializer.Builder::ws);
return this;
}
//-----------------------------------------------------------------------------------------------------------------
// OutputStreamSerializer Properties
//-----------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------
// Parser Properties
//-----------------------------------------------------------------------------------------------------------------
/**
* Parser configuration property: Debug output lines.
*
*
* When parse errors occur, this specifies the number of lines of input before and after the
* error location to be printed as part of the exception message.
*
*
Example:
*
* // Create a parser whose exceptions print out 100 lines before and after the parse error location.
* RestClient client = RestClient
* .create ()
* .json()
* .debug() // Enable debug mode to capture Reader contents as strings.
* .debugOuputLines(100)
* .build();
*
* // Try to parse some bad JSON.
* try {
* client
* .get("/pathToBadJson" )
* .run()
* .getContent().as(Object.class ); // Try to parse it.
* } catch (RestCallException e ) {
* System.err .println(e .getMessage()); // Will display 200 lines of the output.
* }
*
*
* See Also:
* - {@link org.apache.juneau.parser.Parser.Builder#debugOutputLines(int)}
*
*
* @param value
* The new value for this property.
*
The default value is 5 .
* @return This object.
*/
@FluentSetter
public Builder debugOutputLines(int value) {
parsers().forEach(x -> x.debugOutputLines(value));
return this;
}
/**
* Parser configuration property: Strict mode.
*
*
* When enabled, strict mode for the parser is enabled.
*
*
* Strict mode can mean different things for different parsers.
*
*
* Parser class Strict behavior
*
* All reader-based parsers
*
* When enabled, throws {@link ParseException ParseExceptions} on malformed charset input.
* Otherwise, malformed input is ignored.
*
*
*
* {@link JsonParser}
*
* When enabled, throws exceptions on the following invalid JSON syntax:
*
* - Unquoted attributes.
*
- Missing attribute values.
*
- Concatenated strings.
*
- Javascript comments.
*
- Numbers and booleans when Strings are expected.
*
- Numbers valid in Java but not JSON (e.g. octal notation, etc...)
*
*
*
*
*
* Example:
*
* // Create a REST client with JSON parser using strict mode.
* RestClient client = RestClient
* .create ()
* .json()
* .strict()
* .build();
*
* // Try to parse some bad JSON.
* try {
* client
* .get("/pathToBadJson" )
* .run()
* .getContent().as(Object.class ); // Try to parse it.
* } catch (RestCallException e ) {
* // Handle exception.
* }
*
*
* See Also:
* - {@link org.apache.juneau.parser.Parser.Builder#strict()}
*
*
* @return This object.
*/
@FluentSetter
public Builder strict() {
parsers().forEach(org.apache.juneau.parser.Parser.Builder::strict);
return this;
}
/**
* Parser configuration property: Trim parsed strings.
*
*
* When enabled, string values will be trimmed of whitespace using {@link String#trim()} before being added to
* the POJO.
*
*
Example:
*
* // Create a REST client with JSON parser with trim-strings enabled.
* RestClient client = RestClient
* .create ()
* .json()
* .trimStringsOnRead()
* .build();
*
* // Try to parse JSON containing {" foo ":" bar "}.
* Map<String,String> map = client
* .get("/pathToJson" )
* .run()
* .getContent().as(HashMap.class , String.class , String.class );
*
* // Make sure strings are trimmed.
* assertEquals ("bar" , map .get("foo" ));
*
*
* See Also:
* - {@link org.apache.juneau.parser.Parser.Builder#trimStrings()}
*
*
* @return This object.
*/
@FluentSetter
public Builder trimStringsOnRead() {
parsers().forEach(org.apache.juneau.parser.Parser.Builder::trimStrings);
return this;
}
//-----------------------------------------------------------------------------------------------------------------
// ReaderParser Properties
//-----------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------
// InputStreamParser Properties
//-----------------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------
// OpenApi Properties
//-----------------------------------------------------------------------------------------------------------------
/**
* OpenApiCommon configuration property: Default OpenAPI format for HTTP parts.
*
*
* Specifies the format to use for HTTP parts when not otherwise specified via {@link org.apache.juneau.annotation.Schema#format()} for
* the OpenAPI serializer and parser on this client.
*
*
Example:
*
* // Create a REST client with UON part serialization and parsing.
* RestClient client = RestClient
* .create ()
* .oapiFormat(UON )
* .build();
*
* // Set a header with a value in UON format.
* client
* .get("/uri" )
* .header("Foo" , "bar baz" ) // Will be serialized as: 'bar baz'
* .run();
*
*
*
* - {@link org.apache.juneau.httppart.HttpPartFormat}
*
* - {@link org.apache.juneau.httppart.HttpPartFormat#UON UON} - UON notation (e.g.
"'foo bar'" ).
* - {@link org.apache.juneau.httppart.HttpPartFormat#INT32 INT32} - Signed 32 bits.
*
- {@link org.apache.juneau.httppart.HttpPartFormat#INT64 INT64} - Signed 64 bits.
*
- {@link org.apache.juneau.httppart.HttpPartFormat#FLOAT FLOAT} - 32-bit floating point number.
*
- {@link org.apache.juneau.httppart.HttpPartFormat#DOUBLE DOUBLE} - 64-bit floating point number.
*
- {@link org.apache.juneau.httppart.HttpPartFormat#BYTE BYTE} - BASE-64 encoded characters.
*
- {@link org.apache.juneau.httppart.HttpPartFormat#BINARY BINARY} - Hexadecimal encoded octets (e.g.
"00FF" ).
* - {@link org.apache.juneau.httppart.HttpPartFormat#BINARY_SPACED BINARY_SPACED} - Spaced-separated hexadecimal encoded octets (e.g.
"00 FF" ).
* - {@link org.apache.juneau.httppart.HttpPartFormat#DATE DATE} - An RFC3339 full-date.
*
- {@link org.apache.juneau.httppart.HttpPartFormat#DATE_TIME DATE_TIME} - An RFC3339 date-time.
*
- {@link org.apache.juneau.httppart.HttpPartFormat#PASSWORD PASSWORD} - Used to hint UIs the input needs to be obscured.
*
- {@link org.apache.juneau.httppart.HttpPartFormat#NO_FORMAT NO_FORMAT} - (default) Not specified.
*
*
*
* See Also:
* - {@link org.apache.juneau.oapi.OpenApiSerializer.Builder#format(HttpPartFormat)}
*
- {@link org.apache.juneau.oapi.OpenApiParser.Builder#format(HttpPartFormat)}
*
*
* @param value
* The new value for this property.
*
The default value is {@link HttpPartFormat#NO_FORMAT}.
* @return This object.
*/
@FluentSetter
public Builder oapiFormat(HttpPartFormat value) {
serializers().forEach(OpenApiSerializer.Builder.class, x -> x.format(value));
parsers().forEach(OpenApiParser.Builder.class, x -> x.format(value));
partSerializer().builder(OpenApiSerializer.Builder.class).ifPresent(x -> x.format(value));
partParser().builder(OpenApiParser.Builder.class).ifPresent(x -> x.format(value));
return this;
}
/**
* OpenApiCommon configuration property: Default collection format for HTTP parts.
*
*
* Specifies the collection format to use for HTTP parts when not otherwise specified via {@link org.apache.juneau.annotation.Schema#collectionFormat()} for the
* OpenAPI serializer and parser on this client.
*
*
Example:
*
* // Create a REST client with CSV format for http parts.
* RestClient client = RestClient
* .create ()
* .collectionFormat(CSV )
* .build();
*
* // An arbitrary data structure.
* AList list = AList.of (
* "foo" ,
* "bar" ,
* AMap.of (
* "baz" , AList.of ("qux" ,"true" ,"123" )
* )
* );
*
* // Set a header with a comma-separated list.
* client
* .get("/uri" )
* .header("Foo" , list ) // Will be serialized as: foo=bar,baz=qux\,true\,123
* .run();
*
*
*
* - {@link HttpPartCollectionFormat}
*
* - {@link HttpPartCollectionFormat#CSV CSV} - (default) Comma-separated values (e.g.
"foo,bar" ).
* - {@link HttpPartCollectionFormat#SSV SSV} - Space-separated values (e.g.
"foo bar" ).
* - {@link HttpPartCollectionFormat#TSV TSV} - Tab-separated values (e.g.
"foo\tbar" ).
* - {@link HttpPartCollectionFormat#PIPES PIPES} - Pipe-separated values (e.g.
"foo|bar" ).
* - {@link HttpPartCollectionFormat#MULTI MULTI} - Corresponds to multiple parameter instances instead of multiple values for a single instance (e.g.
"foo=bar&foo=baz" ).
* - {@link HttpPartCollectionFormat#UONC UONC} - UON collection notation (e.g.
"@(foo,bar)" ).
*
*
*
* See Also:
* - {@link org.apache.juneau.oapi.OpenApiSerializer.Builder#collectionFormat(HttpPartCollectionFormat)}
*
- {@link org.apache.juneau.oapi.OpenApiParser.Builder#collectionFormat(HttpPartCollectionFormat)}
*
*
* @param value
* The new value for this property.
*
The default value is {@link HttpPartCollectionFormat#NO_COLLECTION_FORMAT}.
* @return This object.
*/
@FluentSetter
public Builder oapiCollectionFormat(HttpPartCollectionFormat value) {
serializers().forEach(OpenApiSerializer.Builder.class, x -> x.collectionFormat(value));
parsers().forEach(OpenApiParser.Builder.class, x -> x.collectionFormat(value));
partSerializer().builder(OpenApiSerializer.Builder.class, x -> x.collectionFormat(value));
partParser().builder(OpenApiParser.Builder.class, x -> x.collectionFormat(value));
return this;
}
//-----------------------------------------------------------------------------------------------------------------
// UON Properties
//-----------------------------------------------------------------------------------------------------------------
/**
* UonSerializer configuration property: Parameter format.
*
*
* Specifies the format of parameters when using the {@link UrlEncodingSerializer} to serialize Form Posts.
*
*
* Specifies the format to use for GET parameter keys and values.
*
*
Example:
*
* // Create a REST client with URL-Encoded serializer that serializes values in plain-text format.
* RestClient client = RestClient
* .create ()
* .urlEnc()
* .paramFormat(PLAINTEXT )
* .build();
*
* // An arbitrary data structure.
* AMap map = AMap.of (
* "foo" , "bar" ,
* "baz" , new String[]{"qux" , "true" , "123" }
* );
*
* // Request body will be serialized as: foo=bar,baz=qux,true,123
* client
* .post("/uri" , map )
* .run();
*
*
*
* - {@link ParamFormat#UON} (default) - Use UON notation for parameters.
*
- {@link ParamFormat#PLAINTEXT} - Use plain text for parameters.
*
*
* See Also:
* - {@link org.apache.juneau.uon.UonSerializer.Builder#paramFormat(ParamFormat)}
*
*
* @param value The new value for this property.
* @return This object.
*/
@FluentSetter
public Builder paramFormat(ParamFormat value) {
serializers().forEach(UonSerializer.Builder.class, x -> x.paramFormat(value));
return this;
}
/**
* UonSerializer configuration property: Parameter format.
*
*
* Specifies the format of parameters when using the {@link UrlEncodingSerializer} to serialize Form Posts.
*
*
* Specifies plaintext as the format to use for GET parameter keys and values.
*
*
Example:
*
* // Create a REST client with URL-Encoded serializer that serializes values in plain-text format.
* RestClient client = RestClient
* .create ()
* .urlEnc()
* .build();
*
* // An arbitrary data structure.
* AMap map = AMap.of (
* "foo" , "bar" ,
* "baz" , new String[]{"qux" , "true" , "123" }
* );
*
* // Request body will be serialized as: foo=bar,baz=qux,true,123
* client
* .post("/uri" , map )
* .run();
*
*
* See Also:
* - {@link org.apache.juneau.uon.UonSerializer.Builder#paramFormatPlain()}
*
*
* @return This object.
*/
@FluentSetter
public Builder paramFormatPlain() {
serializers().forEach(UonSerializer.Builder.class, org.apache.juneau.uon.UonSerializer.Builder::paramFormatPlain);
return this;
}
//
@Override /* GENERATED - org.apache.juneau.Context.Builder */
public Builder annotations(Annotation...values) {
super.annotations(values);
return this;
}
@Override /* GENERATED - org.apache.juneau.Context.Builder */
public Builder apply(AnnotationWorkList work) {
super.apply(work);
return this;
}
@Override /* GENERATED - org.apache.juneau.Context.Builder */
public Builder applyAnnotations(java.lang.Class>...fromClasses) {
super.applyAnnotations(fromClasses);
return this;
}
@Override /* GENERATED - org.apache.juneau.Context.Builder */
public Builder applyAnnotations(Method...fromMethods) {
super.applyAnnotations(fromMethods);
return this;
}
@Override /* GENERATED - org.apache.juneau.Context.Builder */
public Builder cache(Cache value) {
super.cache(value);
return this;
}
@Override /* GENERATED - org.apache.juneau.Context.Builder */
public Builder impl(Context value) {
super.impl(value);
return this;
}
@Override /* GENERATED - org.apache.juneau.Context.Builder */
public Builder type(Class extends org.apache.juneau.Context> value) {
super.type(value);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beanClassVisibility(Visibility value) {
super.beanClassVisibility(value);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beanConstructorVisibility(Visibility value) {
super.beanConstructorVisibility(value);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beanContext(BeanContext value) {
super.beanContext(value);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beanContext(BeanContext.Builder value) {
super.beanContext(value);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beanDictionary(java.lang.Class>...values) {
super.beanDictionary(values);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beanFieldVisibility(Visibility value) {
super.beanFieldVisibility(value);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beanInterceptor(Class> on, Class extends org.apache.juneau.swap.BeanInterceptor>> value) {
super.beanInterceptor(on, value);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beanMethodVisibility(Visibility value) {
super.beanMethodVisibility(value);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beanProperties(Map values) {
super.beanProperties(values);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beanProperties(Class> beanClass, String properties) {
super.beanProperties(beanClass, properties);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beanProperties(String beanClassName, String properties) {
super.beanProperties(beanClassName, properties);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beanPropertiesExcludes(Map values) {
super.beanPropertiesExcludes(values);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beanPropertiesExcludes(Class> beanClass, String properties) {
super.beanPropertiesExcludes(beanClass, properties);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beanPropertiesExcludes(String beanClassName, String properties) {
super.beanPropertiesExcludes(beanClassName, properties);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beanPropertiesReadOnly(Map values) {
super.beanPropertiesReadOnly(values);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beanPropertiesReadOnly(Class> beanClass, String properties) {
super.beanPropertiesReadOnly(beanClass, properties);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beanPropertiesReadOnly(String beanClassName, String properties) {
super.beanPropertiesReadOnly(beanClassName, properties);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beanPropertiesWriteOnly(Map values) {
super.beanPropertiesWriteOnly(values);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beanPropertiesWriteOnly(Class> beanClass, String properties) {
super.beanPropertiesWriteOnly(beanClass, properties);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beanPropertiesWriteOnly(String beanClassName, String properties) {
super.beanPropertiesWriteOnly(beanClassName, properties);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beansRequireDefaultConstructor() {
super.beansRequireDefaultConstructor();
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beansRequireSerializable() {
super.beansRequireSerializable();
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder beansRequireSettersForGetters() {
super.beansRequireSettersForGetters();
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder dictionaryOn(Class> on, java.lang.Class>...values) {
super.dictionaryOn(on, values);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder disableBeansRequireSomeProperties() {
super.disableBeansRequireSomeProperties();
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder disableIgnoreMissingSetters() {
super.disableIgnoreMissingSetters();
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder disableIgnoreTransientFields() {
super.disableIgnoreTransientFields();
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder disableIgnoreUnknownNullBeanProperties() {
super.disableIgnoreUnknownNullBeanProperties();
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder disableInterfaceProxies() {
super.disableInterfaceProxies();
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder findFluentSetters() {
super.findFluentSetters();
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder findFluentSetters(Class> on) {
super.findFluentSetters(on);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder ignoreInvocationExceptionsOnGetters() {
super.ignoreInvocationExceptionsOnGetters();
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder ignoreInvocationExceptionsOnSetters() {
super.ignoreInvocationExceptionsOnSetters();
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder ignoreUnknownBeanProperties() {
super.ignoreUnknownBeanProperties();
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder ignoreUnknownEnumValues() {
super.ignoreUnknownEnumValues();
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder implClass(Class> interfaceClass, Class> implClass) {
super.implClass(interfaceClass, implClass);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder implClasses(Map,Class>> values) {
super.implClasses(values);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder interfaceClass(Class> on, Class> value) {
super.interfaceClass(on, value);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder interfaces(java.lang.Class>...value) {
super.interfaces(value);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder locale(Locale value) {
super.locale(value);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder notBeanClasses(java.lang.Class>...values) {
super.notBeanClasses(values);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder notBeanPackages(String...values) {
super.notBeanPackages(values);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder propertyNamer(Class extends org.apache.juneau.PropertyNamer> value) {
super.propertyNamer(value);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder propertyNamer(Class> on, Class extends org.apache.juneau.PropertyNamer> value) {
super.propertyNamer(on, value);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder sortProperties() {
super.sortProperties();
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder sortProperties(java.lang.Class>...on) {
super.sortProperties(on);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder stopClass(Class> on, Class> value) {
super.stopClass(on, value);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder swap(Class normalClass, Class swappedClass, ThrowingFunction swapFunction) {
super.swap(normalClass, swappedClass, swapFunction);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder swap(Class normalClass, Class swappedClass, ThrowingFunction swapFunction, ThrowingFunction unswapFunction) {
super.swap(normalClass, swappedClass, swapFunction, unswapFunction);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder swaps(java.lang.Class>...values) {
super.swaps(values);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder timeZone(TimeZone value) {
super.timeZone(value);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder typeName(Class> on, String value) {
super.typeName(on, value);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder typePropertyName(String value) {
super.typePropertyName(value);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder typePropertyName(Class> on, String value) {
super.typePropertyName(on, value);
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder useEnumNames() {
super.useEnumNames();
return this;
}
@Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
public Builder useJavaBeanIntrospector() {
super.useJavaBeanIntrospector();
return this;
}
//
//------------------------------------------------------------------------------------------------
// Passthrough methods for HttpClientBuilder.
//------------------------------------------------------------------------------------------------
/**
* Disables automatic redirect handling.
*
* @return This object.
* @see HttpClientBuilder#disableRedirectHandling()
*/
@FluentSetter
public Builder disableRedirectHandling() {
httpClientBuilder().disableRedirectHandling();
return this;
}
/**
* Assigns {@link RedirectStrategy} instance.
*
* Notes:
* - This value can be overridden by the {@link #disableRedirectHandling()} method.
*
*
* @param redirectStrategy New property value.
* @return This object.
* @see HttpClientBuilder#setRedirectStrategy(RedirectStrategy)
*/
@FluentSetter
public Builder redirectStrategy(RedirectStrategy redirectStrategy) {
httpClientBuilder().setRedirectStrategy(redirectStrategy);
return this;
}
/**
* Assigns default {@link CookieSpec} registry which will be used for request execution if not explicitly set in the client execution context.
*
* @param cookieSpecRegistry New property value.
* @return This object.
* @see HttpClientBuilder#setDefaultCookieSpecRegistry(Lookup)
*/
@FluentSetter
public Builder defaultCookieSpecRegistry(Lookup cookieSpecRegistry) {
httpClientBuilder().setDefaultCookieSpecRegistry(cookieSpecRegistry);
return this;
}
/**
* Assigns {@link HttpRequestExecutor} instance.
*
* @param requestExec New property value.
* @return This object.
* @see HttpClientBuilder#setRequestExecutor(HttpRequestExecutor)
*/
@FluentSetter
public Builder requestExecutor(HttpRequestExecutor requestExec) {
httpClientBuilder().setRequestExecutor(requestExec);
return this;
}
/**
* Assigns {@link javax.net.ssl.HostnameVerifier} instance.
*
* Notes:
* - This value can be overridden by the {@link #connectionManager(HttpClientConnectionManager)}
* and the {@link #sslSocketFactory(LayeredConnectionSocketFactory)} methods.
*
*
* @param hostnameVerifier New property value.
* @return This object.
* @see HttpClientBuilder#setSSLHostnameVerifier(HostnameVerifier)
*/
@FluentSetter
public Builder sslHostnameVerifier(HostnameVerifier hostnameVerifier) {
httpClientBuilder().setSSLHostnameVerifier(hostnameVerifier);
return this;
}
/**
* Assigns file containing public suffix matcher.
*
* Notes:
* - Instances of this class can be created with {@link PublicSuffixMatcherLoader}.
*
*
* @param publicSuffixMatcher New property value.
* @return This object.
* @see HttpClientBuilder#setPublicSuffixMatcher(PublicSuffixMatcher)
*/
@FluentSetter
public Builder publicSuffixMatcher(PublicSuffixMatcher publicSuffixMatcher) {
httpClientBuilder().setPublicSuffixMatcher(publicSuffixMatcher);
return this;
}
/**
* Assigns {@link SSLContext} instance.
*
* Notes:
* - This value can be overridden by the {@link #connectionManager(HttpClientConnectionManager)}
* and the {@link #sslSocketFactory(LayeredConnectionSocketFactory)} methods.
*
*
* @param sslContext New property value.
* @return This object.
* @see HttpClientBuilder#setSSLContext(SSLContext)
*/
@FluentSetter
public Builder sslContext(SSLContext sslContext) {
httpClientBuilder().setSSLContext(sslContext);
return this;
}
/**
* Assigns {@link LayeredConnectionSocketFactory} instance.
*
* Notes:
* - This value can be overridden by the {@link #connectionManager(HttpClientConnectionManager)} method.
*
*
* @param sslSocketFactory New property value.
* @return This object.
* @see HttpClientBuilder#setSSLSocketFactory(LayeredConnectionSocketFactory)
*/
@FluentSetter
public Builder sslSocketFactory(LayeredConnectionSocketFactory sslSocketFactory) {
httpClientBuilder().setSSLSocketFactory(sslSocketFactory);
return this;
}
/**
* Assigns maximum total connection value.
*
* Notes:
* - This value can be overridden by the {@link #connectionManager(HttpClientConnectionManager)} method.
*
*
* @param maxConnTotal New property value.
* @return This object.
* @see HttpClientBuilder#setMaxConnTotal(int)
*/
@FluentSetter
public Builder maxConnTotal(int maxConnTotal) {
httpClientBuilder().setMaxConnTotal(maxConnTotal);
return this;
}
/**
* Assigns maximum connection per route value.
*
* Notes:
* - This value can be overridden by the {@link #connectionManager(HttpClientConnectionManager)} method.
*
*
* @param maxConnPerRoute New property value.
* @return This object.
* @see HttpClientBuilder#setMaxConnPerRoute(int)
*/
@FluentSetter
public Builder maxConnPerRoute(int maxConnPerRoute) {
httpClientBuilder().setMaxConnPerRoute(maxConnPerRoute);
return this;
}
/**
* Assigns default {@link SocketConfig}.
*
* Notes:
* - This value can be overridden by the {@link #connectionManager(HttpClientConnectionManager)} method.
*
*
* @param config New property value.
* @return This object.
* @see HttpClientBuilder#setDefaultSocketConfig(SocketConfig)
*/
@FluentSetter
public Builder defaultSocketConfig(SocketConfig config) {
httpClientBuilder().setDefaultSocketConfig(config);
return this;
}
/**
* Assigns default {@link ConnectionConfig}.
*
* Notes:
* - This value can be overridden by the {@link #connectionManager(HttpClientConnectionManager)} method.
*
*
* @param config New property value.
* @return This object.
* @see HttpClientBuilder#setDefaultConnectionConfig(ConnectionConfig)
*/
@FluentSetter
public Builder defaultConnectionConfig(ConnectionConfig config) {
httpClientBuilder().setDefaultConnectionConfig(config);
return this;
}
/**
* Sets maximum time to live for persistent connections.
*
* Notes:
* - This value can be overridden by the {@link #connectionManager(HttpClientConnectionManager)} method.
*
*
* @param connTimeToLive New property value.
* @param connTimeToLiveTimeUnit New property value.
* @return This object.
* @see HttpClientBuilder#setConnectionTimeToLive(long,TimeUnit)
*/
@FluentSetter
public Builder connectionTimeToLive(long connTimeToLive, TimeUnit connTimeToLiveTimeUnit) {
httpClientBuilder().setConnectionTimeToLive(connTimeToLive, connTimeToLiveTimeUnit);
return this;
}
/**
* Assigns {@link ConnectionReuseStrategy} instance.
*
* @param reuseStrategy New property value.
* @return This object.
* @see HttpClientBuilder#setConnectionReuseStrategy(ConnectionReuseStrategy)
*/
@FluentSetter
public Builder connectionReuseStrategy(ConnectionReuseStrategy reuseStrategy) {
httpClientBuilder().setConnectionReuseStrategy(reuseStrategy);
return this;
}
/**
* Assigns {@link ConnectionKeepAliveStrategy} instance.
*
* @param keepAliveStrategy New property value.
* @return This object.
* @see HttpClientBuilder#setKeepAliveStrategy(ConnectionKeepAliveStrategy)
*/
@FluentSetter
public Builder keepAliveStrategy(ConnectionKeepAliveStrategy keepAliveStrategy) {
httpClientBuilder().setKeepAliveStrategy(keepAliveStrategy);
return this;
}
/**
* Assigns {@link AuthenticationStrategy} instance for target host authentication.
*
* @param targetAuthStrategy New property value.
* @return This object.
* @see HttpClientBuilder#setTargetAuthenticationStrategy(AuthenticationStrategy)
*/
@FluentSetter
public Builder targetAuthenticationStrategy(AuthenticationStrategy targetAuthStrategy) {
httpClientBuilder().setTargetAuthenticationStrategy(targetAuthStrategy);
return this;
}
/**
* Assigns {@link AuthenticationStrategy} instance for proxy authentication.
*
* @param proxyAuthStrategy New property value.
* @return This object.
* @see HttpClientBuilder#setProxyAuthenticationStrategy(AuthenticationStrategy)
*/
@FluentSetter
public Builder proxyAuthenticationStrategy(AuthenticationStrategy proxyAuthStrategy) {
httpClientBuilder().setProxyAuthenticationStrategy(proxyAuthStrategy);
return this;
}
/**
* Assigns {@link UserTokenHandler} instance.
*
* Notes:
* - This value can be overridden by the {@link #disableConnectionState()} method.
*
*
* @param userTokenHandler New property value.
* @return This object.
* @see HttpClientBuilder#setUserTokenHandler(UserTokenHandler)
*/
@FluentSetter
public Builder userTokenHandler(UserTokenHandler userTokenHandler) {
httpClientBuilder().setUserTokenHandler(userTokenHandler);
return this;
}
/**
* Disables connection state tracking.
*
* @return This object.
* @see HttpClientBuilder#disableConnectionState()
*/
@FluentSetter
public Builder disableConnectionState() {
httpClientBuilder().disableConnectionState();
return this;
}
/**
* Assigns {@link SchemePortResolver} instance.
*
* @param schemePortResolver New property value.
* @return This object.
* @see HttpClientBuilder#setSchemePortResolver(SchemePortResolver)
*/
@FluentSetter
public Builder schemePortResolver(SchemePortResolver schemePortResolver) {
httpClientBuilder().setSchemePortResolver(schemePortResolver);
return this;
}
/**
* Adds this protocol interceptor to the head of the protocol processing list.
*
* Notes:
* - This value can be overridden by the {@link #httpProcessor(HttpProcessor)} method.
*
*
* @param itcp New property value.
* @return This object.
* @see HttpClientBuilder#addInterceptorFirst(HttpResponseInterceptor)
*/
@FluentSetter
public Builder addInterceptorFirst(HttpResponseInterceptor itcp) {
httpClientBuilder().addInterceptorFirst(itcp);
return this;
}
/**
* Adds this protocol interceptor to the tail of the protocol processing list.
*
* Notes:
* - This value can be overridden by the {@link #httpProcessor(HttpProcessor)} method.
*
*
* @param itcp New property value.
* @return This object.
* @see HttpClientBuilder#addInterceptorLast(HttpResponseInterceptor)
*/
@FluentSetter
public Builder addInterceptorLast(HttpResponseInterceptor itcp) {
httpClientBuilder().addInterceptorLast(itcp);
return this;
}
/**
* Adds this protocol interceptor to the head of the protocol processing list.
*
* Notes:
* - This value can be overridden by the {@link #httpProcessor(HttpProcessor)} method.
*
*
* @param itcp New property value.
* @return This object.
* @see HttpClientBuilder#addInterceptorFirst(HttpRequestInterceptor)
*/
@FluentSetter
public Builder addInterceptorFirst(HttpRequestInterceptor itcp) {
httpClientBuilder().addInterceptorFirst(itcp);
return this;
}
/**
* Adds this protocol interceptor to the tail of the protocol processing list.
*
* Notes:
* - This value can be overridden by the {@link #httpProcessor(HttpProcessor)} method.
*
*
* @param itcp New property value.
* @return This object.
* @see HttpClientBuilder#addInterceptorLast(HttpRequestInterceptor)
*/
@FluentSetter
public Builder addInterceptorLast(HttpRequestInterceptor itcp) {
httpClientBuilder().addInterceptorLast(itcp);
return this;
}
/**
* Disables state (cookie) management.
*
* Notes:
* - This value can be overridden by the {@link #httpProcessor(HttpProcessor)} method.
*
*
* @return This object.
* @see HttpClientBuilder#disableCookieManagement()
*/
@FluentSetter
public Builder disableCookieManagement() {
httpClientBuilder().disableCookieManagement();
return this;
}
/**
* Disables automatic content decompression.
*
* Notes:
* - This value can be overridden by the {@link #httpProcessor(HttpProcessor)} method.
*
*
* @return This object.
* @see HttpClientBuilder#disableContentCompression()
*/
@FluentSetter
public Builder disableContentCompression() {
httpClientBuilder().disableContentCompression();
return this;
}
/**
* Disables authentication scheme caching.
*
* Notes:
* - This value can be overridden by the {@link #httpProcessor(HttpProcessor)} method.
*
*
* @return This object.
* @see HttpClientBuilder#disableAuthCaching()
*/
@FluentSetter
public Builder disableAuthCaching() {
httpClientBuilder().disableAuthCaching();
return this;
}
/**
* Assigns {@link HttpProcessor} instance.
*
* @param httpprocessor New property value.
* @return This object.
* @see HttpClientBuilder#setHttpProcessor(HttpProcessor)
*/
@FluentSetter
public Builder httpProcessor(HttpProcessor httpprocessor) {
httpClientBuilder().setHttpProcessor(httpprocessor);
return this;
}
/**
* Assigns {@link HttpRequestRetryHandler} instance.
*
* Notes:
* - This value can be overridden by the {@link #disableAutomaticRetries()} method.
*
*
* @param retryHandler New property value.
* @return This object.
* @see HttpClientBuilder#setRetryHandler(HttpRequestRetryHandler)
*/
@FluentSetter
public Builder retryHandler(HttpRequestRetryHandler retryHandler) {
httpClientBuilder().setRetryHandler(retryHandler);
return this;
}
/**
* Disables automatic request recovery and re-execution.
*
* @return This object.
* @see HttpClientBuilder#disableAutomaticRetries()
*/
@FluentSetter
public Builder disableAutomaticRetries() {
httpClientBuilder().disableAutomaticRetries();
return this;
}
/**
* Assigns default proxy value.
*
* Notes:
* - This value can be overridden by the {@link #routePlanner(HttpRoutePlanner)} method.
*
*
* @param proxy New property value.
* @return This object.
* @see HttpClientBuilder#setProxy(HttpHost)
*/
@FluentSetter
public Builder proxy(HttpHost proxy) {
httpClientBuilder().setProxy(proxy);
return this;
}
/**
* Assigns {@link HttpRoutePlanner} instance.
*
* @param routePlanner New property value.
* @return This object.
* @see HttpClientBuilder#setRoutePlanner(HttpRoutePlanner)
*/
@FluentSetter
public Builder routePlanner(HttpRoutePlanner routePlanner) {
httpClientBuilder().setRoutePlanner(routePlanner);
return this;
}
/**
* Assigns {@link ConnectionBackoffStrategy} instance.
*
* @param connectionBackoffStrategy New property value.
* @return This object.
* @see HttpClientBuilder#setConnectionBackoffStrategy(ConnectionBackoffStrategy)
*/
@FluentSetter
public Builder connectionBackoffStrategy(ConnectionBackoffStrategy connectionBackoffStrategy) {
httpClientBuilder().setConnectionBackoffStrategy(connectionBackoffStrategy);
return this;
}
/**
* Assigns {@link BackoffManager} instance.
*
* @param backoffManager New property value.
* @return This object.
* @see HttpClientBuilder#setBackoffManager(BackoffManager)
*/
@FluentSetter
public Builder backoffManager(BackoffManager backoffManager) {
httpClientBuilder().setBackoffManager(backoffManager);
return this;
}
/**
* Assigns {@link ServiceUnavailableRetryStrategy} instance.
*
* @param serviceUnavailStrategy New property value.
* @return This object.
* @see HttpClientBuilder#setServiceUnavailableRetryStrategy(ServiceUnavailableRetryStrategy)
*/
@FluentSetter
public Builder serviceUnavailableRetryStrategy(ServiceUnavailableRetryStrategy serviceUnavailStrategy) {
httpClientBuilder().setServiceUnavailableRetryStrategy(serviceUnavailStrategy);
return this;
}
/**
* Assigns default {@link CookieStore} instance which will be used for request execution if not explicitly set in the client execution context.
*
* @param cookieStore New property value.
* @return This object.
* @see HttpClientBuilder#setDefaultCookieStore(CookieStore)
*/
@FluentSetter
public Builder defaultCookieStore(CookieStore cookieStore) {
httpClientBuilder().setDefaultCookieStore(cookieStore);
return this;
}
/**
* Assigns default {@link CredentialsProvider} instance which will be used for request execution if not explicitly set in the client execution context.
*
* @param credentialsProvider New property value.
* @return This object.
* @see HttpClientBuilder#setDefaultCredentialsProvider(CredentialsProvider)
*/
@FluentSetter
public Builder defaultCredentialsProvider(CredentialsProvider credentialsProvider) {
httpClientBuilder().setDefaultCredentialsProvider(credentialsProvider);
return this;
}
/**
* Assigns default {@link org.apache.http.auth.AuthScheme} registry which will be used for request execution if not explicitly set in the client execution context.
*
* @param authSchemeRegistry New property value.
* @return This object.
* @see HttpClientBuilder#setDefaultAuthSchemeRegistry(Lookup)
*/
@FluentSetter
public Builder defaultAuthSchemeRegistry(Lookup authSchemeRegistry) {
httpClientBuilder().setDefaultAuthSchemeRegistry(authSchemeRegistry);
return this;
}
/**
* Assigns a map of {@link org.apache.http.client.entity.InputStreamFactory InputStreamFactories} to be used for automatic content decompression.
*
* @param contentDecoderMap New property value.
* @return This object.
* @see HttpClientBuilder#setContentDecoderRegistry(Map)
*/
@FluentSetter
public Builder contentDecoderRegistry(Map contentDecoderMap) {
httpClientBuilder().setContentDecoderRegistry(contentDecoderMap);
return this;
}
/**
* Assigns default {@link RequestConfig} instance which will be used for request execution if not explicitly set in the client execution context.
*
* @param config New property value.
* @return This object.
* @see HttpClientBuilder#setDefaultRequestConfig(RequestConfig)
*/
@FluentSetter
public Builder defaultRequestConfig(RequestConfig config) {
httpClientBuilder().setDefaultRequestConfig(config);
return this;
}
/**
* Use system properties when creating and configuring default implementations.
*
* @return This object.
* @see HttpClientBuilder#useSystemProperties()
*/
@FluentSetter
public Builder useSystemProperties() {
httpClientBuilder().useSystemProperties();
return this;
}
/**
* Makes this instance of {@link HttpClient} proactively evict expired connections from the connection pool using a background thread.
*
* Notes:
* - One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order to stop and release the background thread.
*
- This method has no effect if the instance of {@link HttpClient} is configured to use a shared connection manager.
*
- This method may not be used when the instance of {@link HttpClient} is created inside an EJB container.
*
*
* @return This object.
* @see HttpClientBuilder#evictExpiredConnections()
*/
@FluentSetter
public Builder evictExpiredConnections() {
httpClientBuilder().evictExpiredConnections();
return this;
}
/**
* Makes this instance of {@link HttpClient} proactively evict idle connections from the connection pool using a background thread.
*
* Notes:
* - One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order to stop and release the background thread.
*
- This method has no effect if the instance of {@link HttpClient} is configured to use a shared connection manager.
*
- This method may not be used when the instance of {@link HttpClient} is created inside an EJB container.
*
*
* @param maxIdleTime New property value.
* @param maxIdleTimeUnit New property value.
* @return This object.
* @see HttpClientBuilder#evictIdleConnections(long,TimeUnit)
*/
@FluentSetter
public Builder evictIdleConnections(long maxIdleTime, TimeUnit maxIdleTimeUnit) {
httpClientBuilder().evictIdleConnections(maxIdleTime, maxIdleTimeUnit);
return this;
}
}
//-------------------------------------------------------------------------------------------------------------------
// Instance
//-------------------------------------------------------------------------------------------------------------------
final HeaderList headerData;
final PartList queryData, formData, pathData;
final CloseableHttpClient httpClient;
private final HttpClientConnectionManager connectionManager;
private final boolean keepHttpClientOpen, detectLeaks, skipEmptyHeaderData, skipEmptyQueryData, skipEmptyFormData;
private final BeanStore beanStore;
private final UrlEncodingSerializer urlEncodingSerializer; // Used for form posts only.
final HttpPartSerializer partSerializer;
final HttpPartParser partParser;
private final RestCallHandler callHandler;
private final String rootUrl;
private volatile boolean isClosed = false;
private final StackTraceElement[] creationStack;
private final Logger logger;
final DetailLevel logRequests;
final BiPredicate logRequestsPredicate;
final Level logRequestsLevel;
final boolean ignoreErrors;
private final boolean logToConsole;
private final PrintStream console;
private StackTraceElement[] closedStack;
private static final ConcurrentHashMap,Context> requestContexts = new ConcurrentHashMap<>();
// These are read directly by RestCall.
final SerializerSet serializers;
final ParserSet parsers;
Predicate errorCodes;
final RestCallInterceptor[] interceptors;
private final Map, HttpPartParser> partParsers = new ConcurrentHashMap<>();
private final Map, HttpPartSerializer> partSerializers = new ConcurrentHashMap<>();
// This is lazy-created.
private volatile ExecutorService executorService;
private final boolean executorServiceShutdownOnClose;
private static final
BiPredicate LOG_REQUESTS_PREDICATE_DEFAULT = (req,res) -> true;
/**
* Constructor.
*
* @param builder The builder for this client.
*/
public RestClient(Builder builder) {
super(builder);
beanStore = builder.beanStore
.addBean(RestClient.class, this);
httpClient = builder.getHttpClient();
headerData = builder.headers().copy();
queryData = builder.queryData().copy();
formData = builder.formData().copy();
pathData = builder.pathData().copy();
callHandler = builder.callHandler().run();
skipEmptyHeaderData = builder.skipEmptyHeaderData;
skipEmptyQueryData = builder.skipEmptyQueryData;
skipEmptyFormData = builder.skipEmptyFormData;
rootUrl = builder.rootUrl;
errorCodes = builder.errorCodes;
connectionManager = builder.connectionManager;
console = builder.console != null ? builder.console : System.err;
executorService = builder.executorService;
executorServiceShutdownOnClose = builder.executorServiceShutdownOnClose;
ignoreErrors = builder.ignoreErrors;
keepHttpClientOpen = builder.keepHttpClientOpen;
detectLeaks = builder.detectLeaks;
logger = builder.logger != null ? builder.logger : Logger.getLogger(RestClient.class.getName());
logToConsole = builder.logToConsole || isDebug();
logRequests = builder.logRequests != null ? builder.logRequests : isDebug() ? DetailLevel.FULL : DetailLevel.NONE;
logRequestsLevel = builder.logRequestsLevel != null ? builder.logRequestsLevel : isDebug() ? Level.WARNING : Level.OFF;
logRequestsPredicate = builder.logRequestsPredicate != null ? builder.logRequestsPredicate : LOG_REQUESTS_PREDICATE_DEFAULT;
interceptors = builder.interceptors != null ? builder.interceptors.toArray(EMPTY_REST_CALL_INTERCEPTORS) : EMPTY_REST_CALL_INTERCEPTORS;
serializers = builder.serializers().build();
parsers = builder.parsers().build();
partSerializer = builder.partSerializer().create();
partParser = builder.partParser().create();
urlEncodingSerializer = builder.urlEncodingSerializer().build();
creationStack = isDebug() ? Thread.currentThread().getStackTrace() : null;
init();
}
@Override /* Context */
public Builder copy() {
throw new NoSuchMethodError("Not implemented.");
}
/**
* Perform optional initialization on builder before it is used.
*
*
* Default behavior is a no-op.
*
* @param builder The builder to initialize.
*/
protected void init(RestClient.Builder builder) {}
/**
* Gets called add the end of the constructor call to perform any post-initialization.
*/
protected void init() {
}
/**
* Calls {@link CloseableHttpClient#close()} on the underlying {@link CloseableHttpClient}.
*
*
* It's good practice to call this method after the client is no longer used.
*
* @throws IOException Thrown by underlying stream.
*/
@Override
public void close() throws IOException {
isClosed = true;
if (! keepHttpClientOpen)
httpClient.close();
if (executorService != null && executorServiceShutdownOnClose)
executorService.shutdown();
if (creationStack != null)
closedStack = Thread.currentThread().getStackTrace();
}
/**
* Same as {@link #close()}, but ignores any exceptions.
*/
public void closeQuietly() {
isClosed = true;
try {
if (! keepHttpClientOpen)
httpClient.close();
if (executorService != null && executorServiceShutdownOnClose)
executorService.shutdown();
} catch (Throwable t) {}
if (creationStack != null)
closedStack = Thread.currentThread().getStackTrace();
}
/**
* Entrypoint for executing all requests and returning a response.
*
*
* Subclasses can override this method to provide specialized handling.
*
*
* The behavior of this method can also be modified by specifying a different {@link RestCallHandler}.
*
*
See Also:
* - {@link Builder#callHandler()}
*
*
* @param target The target host for the request.
*
Implementations may accept null if they can still determine a route, for example to a default
* target or by inspecting the request.
* @param request The request to execute.
* @param context The context to use for the execution, or null to use the default context.
* @return
* The response to the request.
*
This is always a final response, never an intermediate response with an 1xx status code.
*
Whether redirects or authentication challenges will be returned or handled automatically depends on the
* implementation and configuration of this client.
* @throws IOException In case of a problem or the connection was aborted.
* @throws ClientProtocolException In case of an http protocol error.
*/
protected HttpResponse run(HttpHost target, HttpRequest request, HttpContext context) throws ClientProtocolException, IOException {
return callHandler.run(target, request, context);
}
/**
* Perform a GET request against the specified URI.
*
* @param uri
* The URI of the remote REST resource.
*
Can be any of the following types:
*
* - {@link URIBuilder}
*
- {@link URI}
*
- {@link URL}
*
- {@link String}
*
- {@link Object} - Converted to
String using toString()
*
* @return
* A {@link RestRequest} object that can be further tailored before executing the request and getting the response
* as a parsed object.
* @throws RestCallException If any authentication errors occurred.
*/
public RestRequest get(Object uri) throws RestCallException {
return request(op("GET", uri, NO_BODY));
}
/**
* Perform a GET request against the root URI.
*
* @return
* A {@link RestRequest} object that can be further tailored before executing the request and getting the response
* as a parsed object.
* @throws RestCallException If any authentication errors occurred.
*/
public RestRequest get() throws RestCallException {
return request(op("GET", null, NO_BODY));
}
/**
* Perform a PUT request against the specified URI.
*
* @param uri
* The URI of the remote REST resource.
*
Can be any of the following types:
*
* - {@link URIBuilder}
*
- {@link URI}
*
- {@link URL}
*
- {@link String}
*
- {@link Object} - Converted to
String using toString()
*
* @param body
* The object to serialize and transmit to the URI as the body of the request.
* Can be of the following types:
*
* -
* {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource.
*
-
* {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource.
*
-
* {@link Object} - POJO to be converted to text using the {@link Serializer} registered with the
* {@link RestClient}.
*
-
* {@link HttpEntity} / {@link HttpResource} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient.
*
-
* {@link PartList} - Converted to a URL-encoded FORM post.
*
-
* {@link Supplier} - A supplier of anything on this list.
*
* @return
* A {@link RestRequest} object that can be further tailored before executing the request
* and getting the response as a parsed object.
* @throws RestCallException If any authentication errors occurred.
*/
public RestRequest put(Object uri, Object body) throws RestCallException {
return request(op("PUT", uri, body));
}
/**
* Perform a PUT request against the specified URI using a plain text body bypassing the serializer.
*
* @param uri
* The URI of the remote REST resource.
*
Can be any of the following types:
*
* - {@link URIBuilder}
*
- {@link URI}
*
- {@link URL}
*
- {@link String}
*
- {@link Object} - Converted to
String using toString()
*
* @param body
* The object to serialize and transmit to the URI as the body of the request bypassing the serializer.
* @param contentType The content type of the request.
* @return
* A {@link RestRequest} object that can be further tailored before executing the request
* and getting the response as a parsed object.
* @throws RestCallException If any authentication errors occurred.
*/
public RestRequest put(Object uri, String body, ContentType contentType) throws RestCallException {
return request(op("PUT", uri, stringBody(body))).header(contentType);
}
/**
* Same as {@link #put(Object, Object)} but don't specify the input yet.
*
*
* You must call either {@link RestRequest#content(Object)} or {@link RestRequest#formData(String, Object)}
* to set the contents on the result object.
*
* @param uri
* The URI of the remote REST resource.
*
Can be any of the following types:
*
* - {@link URIBuilder}
*
- {@link URI}
*
- {@link URL}
*
- {@link String}
*
- {@link Object} - Converted to
String using toString()
*
* @return
* A {@link RestRequest} object that can be further tailored before executing the request and getting the response
* as a parsed object.
* @throws RestCallException REST call failed.
*/
public RestRequest put(Object uri) throws RestCallException {
return request(op("PUT", uri, NO_BODY));
}
/**
* Perform a POST request against the specified URI.
*
* Notes:
* - Use {@link #formPost(Object, Object)} for
application/x-www-form-urlencoded form posts.
*
*
* @param uri
* The URI of the remote REST resource.
*
Can be any of the following types:
*
* - {@link URIBuilder}
*
- {@link URI}
*
- {@link URL}
*
- {@link String}
*
- {@link Object} - Converted to
String using toString()
*
* @param body
* The object to serialize and transmit to the URI as the body of the request.
* Can be of the following types:
*
* -
* {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource.
*
-
* {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource.
*
-
* {@link Object} - POJO to be converted to text using the {@link Serializer} registered with the
* {@link RestClient}.
*
-
* {@link HttpEntity} / {@link HttpResource} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient.
*
-
* {@link PartList} - Converted to a URL-encoded FORM post.
*
-
* {@link Supplier} - A supplier of anything on this list.
*
* @return
* A {@link RestRequest} object that can be further tailored before executing the request and getting the response
* as a parsed object.
* @throws RestCallException If any authentication errors occurred.
*/
public RestRequest post(Object uri, Object body) throws RestCallException {
return request(op("POST", uri, body));
}
/**
* Perform a POST request against the specified URI as a plain text body bypassing the serializer.
*
* @param uri
* The URI of the remote REST resource.
*
Can be any of the following types:
*
* - {@link URIBuilder}
*
- {@link URI}
*
- {@link URL}
*
- {@link String}
*
- {@link Object} - Converted to
String using toString()
*
* @param body
* The object to serialize and transmit to the URI as the body of the request bypassing the serializer.
* @param contentType
* The content type of the request.
* @return
* A {@link RestRequest} object that can be further tailored before executing the request and getting the response
* as a parsed object.
* @throws RestCallException If any authentication errors occurred.
*/
public RestRequest post(Object uri, String body, ContentType contentType) throws RestCallException {
return request(op("POST", uri, stringBody(body))).header(contentType);
}
/**
* Same as {@link #post(Object, Object)} but don't specify the input yet.
*
*
* You must call either {@link RestRequest#content(Object)} or {@link RestRequest#formData(String, Object)} to set the
* contents on the result object.
*
*
Notes:
* - Use {@link #formPost(Object, Object)} for
application/x-www-form-urlencoded form posts.
*
*
* @param uri
* The URI of the remote REST resource.
*
Can be any of the following types:
*
* - {@link URIBuilder}
*
- {@link URI}
*
- {@link URL}
*
- {@link String}
*
- {@link Object} - Converted to
String using toString()
*
* @return
* A {@link RestRequest} object that can be further tailored before executing the request and getting the response
* as a parsed object.
* @throws RestCallException REST call failed.
*/
public RestRequest post(Object uri) throws RestCallException {
return request(op("POST", uri, NO_BODY));
}
/**
* Perform a DELETE request against the specified URI.
*
* @param uri
* The URI of the remote REST resource.
*
Can be any of the following types:
*
* - {@link URIBuilder}
*
- {@link URI}
*
- {@link URL}
*
- {@link String}
*
- {@link Object} - Converted to
String using toString()
*
* @return
* A {@link RestRequest} object that can be further tailored before executing the request and getting the response
* as a parsed object.
* @throws RestCallException If any authentication errors occurred.
*/
public RestRequest delete(Object uri) throws RestCallException {
return request(op("DELETE", uri, NO_BODY));
}
/**
* Perform an OPTIONS request against the specified URI.
*
* @param uri
* The URI of the remote REST resource.
*
Can be any of the following types:
*
* - {@link URIBuilder}
*
- {@link URI}
*
- {@link URL}
*
- {@link String}
*
- {@link Object} - Converted to
String using toString()
*
* @return
* A {@link RestRequest} object that can be further tailored before executing the request and getting the response
* as a parsed object.
* @throws RestCallException If any authentication errors occurred.
*/
public RestRequest options(Object uri) throws RestCallException {
return request(op("OPTIONS", uri, NO_BODY));
}
/**
* Perform a HEAD request against the specified URI.
*
* @param uri
* The URI of the remote REST resource.
*
Can be any of the following types:
*
* - {@link URIBuilder}
*
- {@link URI}
*
- {@link URL}
*
- {@link String}
*
- {@link Object} - Converted to
String using toString()
*
* @return
* A {@link RestRequest} object that can be further tailored before executing the request and getting the response
* as a parsed object.
* @throws RestCallException If any authentication errors occurred.
*/
public RestRequest head(Object uri) throws RestCallException {
return request(op("HEAD", uri, NO_BODY));
}
/**
* Perform a POST request with a content type of application/x-www-form-urlencoded
* against the specified URI.
*
* @param uri
* The URI of the remote REST resource.
*
Can be any of the following types:
*
* - {@link URIBuilder}
*
- {@link URI}
*
- {@link URL}
*
- {@link String}
*
- {@link Object} - Converted to
String using toString()
*
* @param body
* The object to serialize and transmit to the URI as the body of the request.
*
* - {@link NameValuePair} - URL-encoded as a single name-value pair.
*
- {@link NameValuePair} array - URL-encoded as name value pairs.
*
- {@link PartList} - URL-encoded as name value pairs.
*
- {@link Reader}/{@link InputStream}- Streamed directly and
Content-Type set to "application/x-www-form-urlencoded"
* - {@link HttpResource} - Raw contents will be serialized to remote resource. Additional headers and media type will be set on request.
*
- {@link HttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient.
*
- {@link Object} - Converted to a {@link SerializedEntity} using {@link UrlEncodingSerializer} to serialize.
*
- {@link Supplier} - A supplier of anything on this list.
*
* @return
* A {@link RestRequest} object that can be further tailored before executing the request and getting the response
* as a parsed object.
* @throws RestCallException If any authentication errors occurred.
*/
public RestRequest formPost(Object uri, Object body) throws RestCallException {
RestRequest req = request(op("POST", uri, NO_BODY));
try {
if (body instanceof Supplier)
body = ((Supplier>)body).get();
if (body instanceof NameValuePair)
return req.content(new UrlEncodedFormEntity(alist((NameValuePair)body)));
if (body instanceof NameValuePair[])
return req.content(new UrlEncodedFormEntity(alist((NameValuePair[])body)));
if (body instanceof PartList)
return req.content(new UrlEncodedFormEntity(((PartList)body)));
if (body instanceof HttpResource)
((HttpResource)body).getHeaders().forEach(x-> req.header(x));
if (body instanceof HttpEntity) {
HttpEntity e = (HttpEntity)body;
if (e.getContentType() == null)
req.header(ContentType.APPLICATION_FORM_URLENCODED);
return req.content(e);
}
if (body instanceof Reader || body instanceof InputStream)
return req.header(ContentType.APPLICATION_FORM_URLENCODED).content(body);
return req.content(serializedEntity(body, urlEncodingSerializer, null));
} catch (IOException e) {
throw new RestCallException(null, e, "Could not read form post body.");
}
}
/**
* Same as {@link #formPost(Object, Object)} but doesn't specify the input yet.
*
* @param uri
* The URI of the remote REST resource.
*
Can be any of the following types:
*
* - {@link URIBuilder}
*
- {@link URI}
*
- {@link URL}
*
- {@link String}
*
- {@link Object} - Converted to
String using toString()
*
* @return
* A {@link RestRequest} object that can be further tailored before executing the request and getting the response
* as a parsed object.
* @throws RestCallException If any authentication errors occurred.
*/
public RestRequest formPost(Object uri) throws RestCallException {
return request(op("POST", uri, NO_BODY));
}
/**
* Perform a POST request with a content type of application/x-www-form-urlencoded
* against the specified URI.
*
* @param uri
* The URI of the remote REST resource.
*
Can be any of the following types:
*
* - {@link URIBuilder}
*
- {@link URI}
*
- {@link URL}
*
- {@link String}
*
- {@link Object} - Converted to
String using toString()
*
* @param parameters
* The parameters of the form post.
*
The parameters represent name/value pairs and must be an even number of arguments.
*
Parameters are converted to {@link BasicPart} objects.
* @return
* A {@link RestRequest} object that can be further tailored before executing the request and getting the response
* as a parsed object.
* @throws RestCallException If any authentication errors occurred.
*/
public RestRequest formPostPairs(Object uri, String...parameters) throws RestCallException {
return formPost(uri, partList(parameters));
}
/**
* Perform a PATCH request against the specified URI.
*
* @param uri
* The URI of the remote REST resource.
*
Can be any of the following types:
*
* - {@link URIBuilder}
*
- {@link URI}
*
- {@link URL}
*
- {@link String}
*
- {@link Object} - Converted to
String using toString()
*
* @param body
* The object to serialize and transmit to the URI as the body of the request.
* Can be of the following types:
*
* -
* {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource.
*
-
* {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource.
*
-
* {@link HttpResource} - Raw contents will be serialized to remote resource. Additional headers and media type will be set on request.
*
-
* {@link HttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient.
*
-
* {@link Object} - POJO to be converted to text using the {@link Serializer} registered with the
* {@link RestClient}.
*
-
* {@link PartList} - Converted to a URL-encoded FORM post.
*
-
* {@link Supplier} - A supplier of anything on this list.
*
* @return
* A {@link RestRequest} object that can be further tailored before executing the request and getting the response
* as a parsed object.
* @throws RestCallException If any authentication errors occurred.
*/
public RestRequest patch(Object uri, Object body) throws RestCallException {
return request(op("PATCH", uri, body));
}
/**
* Perform a PATCH request against the specified URI as a plain text body bypassing the serializer.
*
* @param uri
* The URI of the remote REST resource.
*
Can be any of the following types:
*
* - {@link URIBuilder}
*
- {@link URI}
*
- {@link URL}
*
- {@link String}
*
- {@link Object} - Converted to
String using toString()
*
* @param body
* The object to serialize and transmit to the URI as the body of the request bypassing the serializer.
* @param contentType
* The content type of the request.
* @return
* A {@link RestRequest} object that can be further tailored before executing the request and getting the response
* as a parsed object.
* @throws RestCallException If any authentication errors occurred.
*/
public RestRequest patch(Object uri, String body, ContentType contentType) throws RestCallException {
return request(op("PATCH", uri, stringBody(body))).header(contentType);
}
/**
* Same as {@link #patch(Object, Object)} but don't specify the input yet.
*
*
* You must call {@link RestRequest#content(Object)} to set the contents on the result object.
*
* @param uri
* The URI of the remote REST resource.
*
Can be any of the following types:
*
* - {@link URIBuilder}
*
- {@link URI}
*
- {@link URL}
*
- {@link String}
*
- {@link Object} - Converted to
String using toString()
*
* @return
* A {@link RestRequest} object that can be further tailored before executing the request and getting the response
* as a parsed object.
* @throws RestCallException REST call failed.
*/
public RestRequest patch(Object uri) throws RestCallException {
return request(op("PATCH", uri, NO_BODY));
}
/**
* Performs a REST call where the entire call is specified in a simple string.
*
*
* This method is useful for performing callbacks when the target of a callback is passed in
* on an initial request, for example to signal when a long-running process has completed.
*
*
* The call string can be any of the following formats:
*
* -
*
"[method] [uri]" - e.g. "GET http://localhost/callback"
* -
*
"[method] [uri] [payload]" - e.g. "POST http://localhost/callback some text payload"
* -
*
"[method] [headers] [uri] [payload]" - e.g. "POST {'Content-Type':'text/json'} http://localhost/callback {'some':'json'}"
*
*
* The payload will always be sent using a simple {@link StringEntity}.
*
* @param callString The call string.
* @return
* A {@link RestRequest} object that can be further tailored before executing the request and getting the response
* as a parsed object.
* @throws RestCallException REST call failed.
*/
public RestRequest callback(String callString) throws RestCallException {
callString = emptyIfNull(callString);
// S01 - Looking for end of method.
// S02 - Found end of method, looking for beginning of URI or headers.
// S03 - Found beginning of headers, looking for end of headers.
// S04 - Found end of headers, looking for beginning of URI.
// S05 - Found beginning of URI, looking for end of URI.
StateMachineState state = S01;
int mark = 0;
String method = null, headers = null, uri = null, content = null;
for (int i = 0; i < callString.length(); i++) {
char c = callString.charAt(i);
if (state == S01) {
if (isWhitespace(c)) {
method = callString.substring(mark, i);
state = S02;
}
} else if (state == S02) {
if (! isWhitespace(c)) {
mark = i;
if (c == '{')
state = S03;
else
state = S05;
}
} else if (state == S03) {
if (c == '}') {
headers = callString.substring(mark, i+1);
state = S04;
}
} else if (state == S04) {
if (! isWhitespace(c)) {
mark = i;
state = S05;
}
} else /* (state == S05) */ {
if (isWhitespace(c)) {
uri = callString.substring(mark, i);
content = callString.substring(i).trim();
break;
}
}
}
if (state != S05)
throw new RestCallException(null, null, "Invalid format for call string. State={0}", state);
try {
RestRequest req = request(method, uri, isNotEmpty(content));
if (headers != null)
JsonMap.ofJson(headers).forEach((k,v) -> req.header(stringHeader(k, stringify(v))));
if (isNotEmpty(content))
req.contentString(content);
return req;
} catch (ParseException e) {
throw new RestCallException(null, e, "Invalid format for call string.");
}
}
/**
* Perform a generic REST call.
*
* @param method The HTTP method.
* @param uri
* The URI of the remote REST resource.
*
Can be any of the following types:
*
* - {@link URIBuilder}
*
- {@link URI}
*
- {@link URL}
*
- {@link String}
*
- {@link Object} - Converted to
String using toString()
*
* @param body
* The HTTP body content.
* Can be of the following types:
*
* -
* {@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource.
*
-
* {@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource.
*
-
* {@link HttpResource} - Raw contents will be serialized to remote resource. Additional headers and media type will be set on request.
*
-
* {@link HttpEntity} - Bypass Juneau serialization and pass HttpEntity directly to HttpClient.
*
-
* {@link Object} - POJO to be converted to text using the {@link Serializer} registered with the
* {@link RestClient}.
*
-
* {@link PartList} - Converted to a URL-encoded FORM post.
*
-
* {@link Supplier} - A supplier of anything on this list.
*
* This parameter is IGNORED if the method type normally does not have content.
* @return
* A {@link RestRequest} object that can be further tailored before executing the request and getting the response
* as a parsed object.
* @throws RestCallException If any authentication errors occurred.
*/
public RestRequest request(String method, Object uri, Object body) throws RestCallException {
return request(op(method, uri, body));
}
/**
* Perform a generic REST call.
*
* @param method The HTTP method.
* @param uri
* The URI of the remote REST resource.
*
Can be any of the following types:
*
* - {@link URIBuilder}
*
- {@link URI}
*
- {@link URL}
*
- {@link String}
*
- {@link Object} - Converted to
String using toString()
*
* @return
* A {@link RestRequest} object that can be further tailored before executing the request and getting the response
* as a parsed object.
* @throws RestCallException If any authentication errors occurred.
*/
public RestRequest request(String method, Object uri) throws RestCallException {
return request(op(method, uri, NO_BODY));
}
/**
* Perform a generic REST call.
*
*
* Typically you're going to use {@link #request(String, Object)} or {@link #request(String, Object, Object)},
* but this method is provided to allow you to perform non-standard HTTP methods (e.g. HTTP FOO).
*
* @param method The method name (e.g. "GET" , "OPTIONS" ).
* @param uri
* The URI of the remote REST resource.
*
Can be any of the following types:
*
* - {@link URIBuilder}
*
- {@link URI}
*
- {@link URL}
*
- {@link String}
*
- {@link Object} - Converted to
String using toString()
*
* @param hasBody Boolean flag indicating if the specified request has content associated with it.
* @return
* A {@link RestRequest} object that can be further tailored before executing the request and getting the response
* as a parsed object.
* @throws RestCallException If any authentication errors occurred.
*/
public RestRequest request(String method, Object uri, boolean hasBody) throws RestCallException {
return request(op(method, uri, NO_BODY).hasContent(hasBody));
}
/**
* Perform an arbitrary request against the specified URI.
*
*
* All requests feed through this method so it can be used to intercept request creations and make modifications
* (such as add headers).
*
* @param op The operation that identifies the HTTP method, URL, and optional payload.
* @return
* A {@link RestRequest} object that can be further tailored before executing the request and getting the response
* as a parsed object.
* @throws RestCallException If any authentication errors occurred.
*/
protected RestRequest request(RestOperation op) throws RestCallException {
if (isClosed) {
Exception e2 = null;
if (closedStack != null) {
e2 = new Exception("Creation stack:");
e2.setStackTrace(closedStack);
throw new RestCallException(null, e2, "RestClient.close() has already been called. This client cannot be reused.");
}
throw new RestCallException(null, null, "RestClient.close() has already been called. This client cannot be reused. Closed location stack trace can be displayed by setting the system property 'org.apache.juneau.rest.client2.RestClient.trackCreation' to true.");
}
RestRequest req = createRequest(toURI(op.getUri(), rootUrl), op.getMethod(), op.hasContent());
onCallInit(req);
req.content(op.getContent());
return req;
}
/**
* Creates a {@link RestRequest} object from the specified {@link HttpRequest} object.
*
*
* Subclasses can override this method to provide their own specialized {@link RestRequest} objects.
*
* @param uri The target.
* @param method The HTTP method (uppercase).
* @param hasBody Whether this method has a request entity.
* @return A new {@link RestRequest} object.
* @throws RestCallException If an exception or non-200 response code occurred during the connection attempt.
*/
protected RestRequest createRequest(URI uri, String method, boolean hasBody) throws RestCallException {
return new RestRequest(this, uri, method, hasBody);
}
/**
* Creates a {@link RestResponse} object from the specified {@link HttpResponse} object.
*
*
* Subclasses can override this method to provide their own specialized {@link RestResponse} objects.
*
* @param request The request creating this response.
* @param httpResponse The response object to wrap.
* @param parser The parser to use to parse the response.
*
* @return A new {@link RestResponse} object.
* @throws RestCallException If an exception or non-200 response code occurred during the connection attempt.
*/
protected RestResponse createResponse(RestRequest request, HttpResponse httpResponse, Parser parser) throws RestCallException {
return new RestResponse(this, request, httpResponse, parser);
}
/**
* Create a new proxy interface against a 3rd-party REST interface.
*
*
* The URI to the REST interface is based on the following values:
*
* - The {@link Remote#path() @Remote(path)} annotation on the interface (
remote-path ).
* - The {@link Builder#rootUrl(Object) rootUrl} on the client (
root-url ).
* - The fully-qualified class name of the interface (
class-name ).
*
*
*
* The URI calculation is as follows:
*
* remote-path - If remote path is absolute.
* root-uri/remote-path - If remote path is relative and root-uri has been specified.
* root-uri/class-name - If remote path is not specified.
*
*
*
* If the information is not available to resolve to an absolute URI, a {@link RemoteMetadataException} is thrown.
*
*
Examples:
*
* package org.apache.foo;
*
* @RemoteResource (path="http://hostname/resturi/myinterface1" )
* public interface MyInterface1 { ... }
*
* @RemoteResource (path="/myinterface2" )
* public interface MyInterface2 { ... }
*
* public interface MyInterface3 { ... }
*
* // Resolves to "http://localhost/resturi/myinterface1"
* MyInterface1 interface1 = RestClient
* .create ()
* .build()
* .getRemote(MyInterface1.class );
*
* // Resolves to "http://hostname/resturi/myinterface2"
* MyInterface2 interface2 = RestClient
* .create ()
* .rootUrl("http://hostname/resturi" )
* .build()
* .getRemote(MyInterface2.class );
*
* // Resolves to "http://hostname/resturi/org.apache.foo.MyInterface3"
* MyInterface3 interface3 = RestClient
* .create ()
* .rootUrl("http://hostname/resturi" )
* .build()
* .getRemote(MyInterface3.class );
*
*
* Notes:
* -
* If you plan on using your proxy in a multi-threaded environment, you'll want to use an underlying
* pooling client connection manager.
*
*
* See Also:
* - REST Proxies
*
*
* @param The interface to create a proxy for.
* @param interfaceClass The interface to create a proxy for.
* @return The new proxy interface.
* @throws RemoteMetadataException If the REST URI cannot be determined based on the information given.
*/
public T getRemote(Class interfaceClass) {
return getRemote(interfaceClass, null);
}
/**
* Same as {@link #getRemote(Class)} except explicitly specifies the URI of the REST interface.
*
* See Also:
* - REST Proxies
*
*
* @param The interface to create a proxy for.
* @param interfaceClass The interface to create a proxy for.
* @param rootUrl The URI of the REST interface.
* @return The new proxy interface.
*/
public T getRemote(Class interfaceClass, Object rootUrl) {
return getRemote(interfaceClass, rootUrl, null, null);
}
/**
* Same as {@link #getRemote(Class, Object)} but allows you to override the serializer and parser used.
*
* See Also:
* - REST Proxies
*
* @param The interface to create a proxy for.
* @param interfaceClass The interface to create a proxy for.
* @param rootUrl The URI of the REST interface.
* @param serializer The serializer used to serialize POJOs to the body of the HTTP request.
* @param parser The parser used to parse POJOs from the body of the HTTP response.
* @return The new proxy interface.
*/
@SuppressWarnings({ "unchecked" })
public T getRemote(final Class interfaceClass, Object rootUrl, final Serializer serializer, final Parser parser) {
if (rootUrl == null)
rootUrl = this.rootUrl;
final String restUrl2 = trimSlashes(emptyIfNull(rootUrl));
return (T)Proxy.newProxyInstance(
interfaceClass.getClassLoader(),
new Class[] { interfaceClass },
new InvocationHandler() {
final RemoteMeta rm = new RemoteMeta(interfaceClass);
@Override /* InvocationHandler */
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
RemoteOperationMeta rom = rm.getOperationMeta(method);
String uri = rom.getFullPath();
if (uri.indexOf("://") == -1)
uri = restUrl2 + '/' + uri;
if (uri.indexOf("://") == -1)
throw new RemoteMetadataException(interfaceClass, "Root URI has not been specified. Cannot construct absolute path to remote resource.");
String httpMethod = rom.getHttpMethod();
RestRequest rc = request(httpMethod, uri, hasContent(httpMethod));
rc.serializer(serializer);
rc.parser(parser);
rm.getHeaders().forEach(x -> rc.header(x));
rom.forEachPathArg(a -> rc.pathArg(a.getName(), args[a.getIndex()], a.getSchema(), a.getSerializer().orElse(partSerializer)));
rom.forEachQueryArg(a -> rc.queryArg(a.getName(), args[a.getIndex()], a.getSchema(), a.getSerializer().orElse(partSerializer), a.isSkipIfEmpty()));
rom.forEachFormDataArg(a -> rc.formDataArg(a.getName(), args[a.getIndex()], a.getSchema(), a.getSerializer().orElse(partSerializer), a.isSkipIfEmpty()));
rom.forEachHeaderArg(a -> rc.headerArg(a.getName(), args[a.getIndex()], a.getSchema(), a.getSerializer().orElse(partSerializer), a.isSkipIfEmpty()));
RemoteOperationArg ba = rom.getContentArg();
if (ba != null)
rc.content(args[ba.getIndex()], ba.getSchema());
rom.forEachRequestArg(rmba -> {
RequestBeanMeta rbm = rmba.getMeta();
Object bean = args[rmba.getIndex()];
if (bean != null) {
for (RequestBeanPropertyMeta p : rbm.getProperties()) {
Object val = safeSupplier(()->p.getGetter().invoke(bean));
HttpPartType pt = p.getPartType();
String pn = p.getPartName();
HttpPartSchema schema = p.getSchema();
if (pt == PATH)
rc.pathArg(pn, val, schema, p.getSerializer().orElse(partSerializer));
else if (val != null) {
if (pt == QUERY)
rc.queryArg(pn, val, schema, p.getSerializer().orElse(partSerializer), schema.isSkipIfEmpty());
else if (pt == FORMDATA)
rc.formDataArg(pn, val, schema, p.getSerializer().orElse(partSerializer), schema.isSkipIfEmpty());
else if (pt == HEADER)
rc.headerArg(pn, val, schema, p.getSerializer().orElse(partSerializer), schema.isSkipIfEmpty());
else /* (pt == HttpPartType.BODY) */
rc.content(val, schema);
}
}
}
});
RemoteOperationReturn ror = rom.getReturns();
if (ror.isFuture()) {
return getExecutorService().submit(() -> {
try {
return executeRemote(interfaceClass, rc, method, rom);
} catch (Exception e) {
throw e;
} catch (Throwable e) {
throw asRuntimeException(e);
}
});
} else if (ror.isCompletableFuture()) {
CompletableFuture