This is an automated email from the ASF dual-hosted git repository. jamesbognar pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push: new 25562e5 RestClient tests. 25562e5 is described below commit 25562e5f6e9141b1fdfb6a1a8c3e131eb46a79c9 Author: JamesBognar <james.bog...@salesforce.com> AuthorDate: Sat Jun 20 10:32:28 2020 -0400 RestClient tests. --- .../org/apache/juneau/http/BasicNameValuePair.java | 10 +- .../java/org/apache/juneau/http/Headerable.java | 32 + .../org/apache/juneau/http/SerializedHeader.java | 12 + .../juneau/http/SerializedNameValuePair.java | 9 +- .../org/apache/juneau/http/header/BasicHeader.java | 12 + .../org/apache/juneau/httppart/HttpPartSchema.java | 17 +- .../juneau/httppart/HttpPartSchemaBuilder.java | 116 +- .../juneau/rest/client2/QueryAnnotationTest.java | 2 +- .../apache/juneau/rest/client2/RestClientTest.java | 179 ++- .../org/apache/juneau/rest/client2/RestClient.java | 60 +- .../juneau/rest/client2/RestClientBuilder.java | 111 +- .../juneau/rest/client2/RestClientUtils.java | 103 -- .../apache/juneau/rest/client2/RestRequest.java | 1579 ++++---------------- 13 files changed, 781 insertions(+), 1461 deletions(-) diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/BasicNameValuePair.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/BasicNameValuePair.java index 6910f0f..952705e 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/BasicNameValuePair.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/BasicNameValuePair.java @@ -17,15 +17,16 @@ import static org.apache.juneau.internal.StringUtils.*; import java.util.function.*; import org.apache.http.*; +import org.apache.juneau.http.header.*; /** * Subclass of {@link NameValuePair} for serializing POJOs as URL-encoded form post entries. - * + * * <p> * The value is serialized using {@link Object#toString()} at the point of reading. This allows the value to be modified * periodically by overriding the method to return different values. */ -public class BasicNameValuePair implements NameValuePair { +public class BasicNameValuePair implements NameValuePair, Headerable { private String name; private Object value; @@ -65,6 +66,11 @@ public class BasicNameValuePair implements NameValuePair { this.value = value; } + @Override /* Headerable */ + public BasicHeader asHeader() { + return BasicHeader.of(name, value); + } + @Override /* NameValuePair */ public String getName() { return name; diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/Headerable.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/Headerable.java new file mode 100644 index 0000000..682c257 --- /dev/null +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/Headerable.java @@ -0,0 +1,32 @@ +// *************************************************************************************************************************** +// * 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.http; + +import org.apache.http.*; + +/** + * Identifies a class that can be converted to a {@link Header} object. + * + * <p> + * Typically used on {@link NameValuePair} classes to allow them to be easily converted to {@link Header} + * objects in a controlled way. + */ +public interface Headerable { + + /** + * Convert the object to a {@link Header}. + * + * @return The object converted to a {@link Header}. + */ + Header asHeader(); +} diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedHeader.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedHeader.java index 94f7eda..032b184 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedHeader.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedHeader.java @@ -133,6 +133,18 @@ public class SerializedHeader extends BasicStringHeader { * @param value The new value for this property. * @return This object (for method chaining). */ + public Builder serializer(HttpPartSerializer value) { + if (value != null) + return serializer(value.createPartSession(null)); + return this; + } + + /** + * Sets the serializer to use for serializing the value to a string value. + * + * @param value The new value for this property. + * @return This object (for method chaining). + */ public Builder serializer(HttpPartSerializerSession value) { return serializer(value, true); } diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedNameValuePair.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedNameValuePair.java index 3ad07e0..519471e 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedNameValuePair.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedNameValuePair.java @@ -35,7 +35,7 @@ import org.apache.juneau.urlencoding.*; * request.setEntity(<jk>new</jk> UrlEncodedFormEntity(params)); * </p> */ -public class SerializedNameValuePair implements NameValuePair { +public class SerializedNameValuePair implements NameValuePair, Headerable { private String name; private Object value; private HttpPartType type; @@ -76,6 +76,11 @@ public class SerializedNameValuePair implements NameValuePair { this.skipIfEmpty = skipIfEmpty; } + @Override /* Headerable */ + public SerializedHeader asHeader() { + return new SerializedHeader(name, value, serializer, schema, skipIfEmpty); + } + SerializedNameValuePair(Builder b) { this.name = b.name; this.value = b.value; @@ -208,6 +213,8 @@ public class SerializedNameValuePair implements NameValuePair { return null; if (schema.getDefault() == null && ! schema.isRequired()) return null; + if (schema.isAllowEmptyValue() && schema.getDefault() == null) + return null; } if (isEmpty(v) && skipIfEmpty && schema.getDefault() == null) return null; diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/header/BasicHeader.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/header/BasicHeader.java index adac8cb..cbc1674 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/header/BasicHeader.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/header/BasicHeader.java @@ -47,6 +47,18 @@ public class BasicHeader implements Header, Cloneable, Serializable { } /** + * Convenience creator. + * + * @param o The name value pair that makes up the header name and value. + * The parameter value. + * <br>Any non-String value will be converted to a String using {@link Object#toString()}. + * @return A new {@link BasicHeader} object. + */ + public static Header of(NameValuePair o) { + return new BasicHeader(o.getName(), o.getValue()); + } + + /** * Convenience creator using supplier. * * <p> diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchema.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchema.java index ae54100..480a064 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchema.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchema.java @@ -1471,20 +1471,25 @@ public class HttpPartSchema { return in == null ? Collections.emptySet() : unmodifiableSet(new LinkedHashSet<>(in)); } - private static Map<String,HttpPartSchema> build(Map<String,HttpPartSchemaBuilder> in, boolean noValidate) { + private static Map<String,HttpPartSchema> build(Map<String,Object> in, boolean noValidate) { if (in == null) return null; Map<String,HttpPartSchema> m = new LinkedHashMap<>(); - for (Map.Entry<String,HttpPartSchemaBuilder> e : in.entrySet()) - m.put(e.getKey(), e.getValue().noValidate(noValidate).build()); + for (Map.Entry<String,Object> e : in.entrySet()) { + Object v = e.getValue(); + m.put(e.getKey(), build(v, noValidate)); + } return unmodifiableMap(m); } - private static HttpPartSchema build(HttpPartSchemaBuilder in, boolean noValidate) { - return in == null ? null : in.noValidate(noValidate).build(); + private static HttpPartSchema build(Object in, boolean noValidate) { + if (in == null) + return null; + if (in instanceof HttpPartSchema) + return (HttpPartSchema)in; + return ((HttpPartSchemaBuilder)in).noValidate(noValidate).build(); } - //----------------------------------------------------------------------------------------------------------------- // Helper methods. //----------------------------------------------------------------------------------------------------------------- diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java index 00cb8c3..c350d4f 100644 --- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java @@ -41,8 +41,8 @@ public class HttpPartSchemaBuilder { Pattern pattern; Number maximum, minimum, multipleOf; Long maxLength, minLength, maxItems, minItems, maxProperties, minProperties; - Map<String,HttpPartSchemaBuilder> properties; - HttpPartSchemaBuilder items, additionalProperties; + Map<String,Object> properties; + Object items, additionalProperties; boolean noValidate; Class<? extends HttpPartParser> parser; Class<? extends HttpPartSerializer> serializer; @@ -1068,6 +1068,35 @@ public class HttpPartSchemaBuilder { return this; } + /** + * <mk>items</mk> field. + * + * <p> + * Describes the type of items in the array. + * <p> + * Required if <c>type</c> is <js>"array"</js>. + * <br>Can only be used if <c>type</c> is <js>"array"</js>. + * + * <p> + * Applicable to the following Swagger schema objects: + * <ul> + * <li>{@doc SwaggerParameterObject Parameter} + * <li>{@doc SwaggerSchemaObject Schema} + * <li>{@doc SwaggerItemsObject Items} + * <li>{@doc SwaggerHeaderObject Header} + * </ul> + * + * @param value + * The new value for this property. + * <br>Ignored if value is <jk>null</jk> or empty. + * @return This object (for method chaining). + */ + public HttpPartSchemaBuilder items(HttpPartSchema value) { + if (value != null) + this.items = value; + return this; + } + HttpPartSchemaBuilder items(OMap value) { if (value != null && ! value.isEmpty()) items = HttpPartSchema.create().apply(value); @@ -1926,6 +1955,31 @@ public class HttpPartSchemaBuilder { } /** + * <mk>properties</mk> field. + * + * <p> + * Applicable to the following Swagger schema objects: + * <ul> + * <li>{@doc SwaggerSchemaObject Schema} + * </ul> + * + * @param key + * The property name. + * @param value + * The new value for this property. + * <br>Ignored if value is <jk>null</jk>. + * @return This object (for method chaining). + */ + public HttpPartSchemaBuilder property(String key, HttpPartSchema value) { + if ( key != null && value != null) { + if (properties == null) + properties = new LinkedHashMap<>(); + properties.put(key, value); + } + return this; + } + + /** * Shortcut for <c>property(key, value)</c>. * * <p> @@ -1945,6 +1999,26 @@ public class HttpPartSchemaBuilder { return property(key, value); } + /** + * Shortcut for <c>property(key, value)</c>. + * + * <p> + * Applicable to the following Swagger schema objects: + * <ul> + * <li>{@doc SwaggerSchemaObject Schema} + * </ul> + * + * @param key + * The property name. + * @param value + * The new value for this property. + * <br>Ignored if value is <jk>null</jk>. + * @return This object (for method chaining). + */ + public HttpPartSchemaBuilder p(String key, HttpPartSchema value) { + return property(key, value); + } + private HttpPartSchemaBuilder properties(OMap value) { if (value != null && ! value.isEmpty()) for (Map.Entry<String,Object> e : value.entrySet()) @@ -1973,6 +2047,26 @@ public class HttpPartSchemaBuilder { } /** + * <mk>additionalProperties</mk> field. + * + * <p> + * Applicable to the following Swagger schema objects: + * <ul> + * <li>{@doc SwaggerSchemaObject Schema} + * </ul> + * + * @param value + * The new value for this property. + * <br>Ignored if value is <jk>null</jk> or empty. + * @return This object (for method chaining). + */ + public HttpPartSchemaBuilder additionalProperties(HttpPartSchema value) { + if (value != null) + additionalProperties = value; + return this; + } + + /** * Shortcut for <c>additionalProperties(value)</c> * * <p> @@ -1990,6 +2084,24 @@ public class HttpPartSchemaBuilder { return additionalProperties(value); } + /** + * Shortcut for <c>additionalProperties(value)</c> + * + * <p> + * Applicable to the following Swagger schema objects: + * <ul> + * <li>{@doc SwaggerSchemaObject Schema} + * </ul> + * + * @param value + * The new value for this property. + * <br>Ignored if value is <jk>null</jk> or empty. + * @return This object (for method chaining). + */ + public HttpPartSchemaBuilder ap(HttpPartSchema value) { + return additionalProperties(value); + } + private HttpPartSchemaBuilder additionalProperties(OMap value) { if (value != null && ! value.isEmpty()) additionalProperties = HttpPartSchema.create().apply(value); diff --git a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/QueryAnnotationTest.java b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/QueryAnnotationTest.java index ad89bd1..2f14e32 100644 --- a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/QueryAnnotationTest.java +++ b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/QueryAnnotationTest.java @@ -75,7 +75,7 @@ public class QueryAnnotationTest { @RemoteMethod(path="a") String getA06b(@Query("*") Map<String,Bean> b); @RemoteMethod(path="a") String getA06c(@Query Map<String,Bean> b); @RemoteMethod(path="a") String getA06d(@Query(n="x",cf="uon") Map<String,Bean> b); - @RemoteMethod(path="a") String getA06e(@Query(cf="uon") Map<String,Bean> b); + @RemoteMethod(path="a") String getA06e(@Query(f="uon") Map<String,Bean> b); @RemoteMethod(path="a") String getA07a(@Query("*") Reader b); @RemoteMethod(path="a") String getA07b(@Query Reader b); @RemoteMethod(path="a") String getA08a(@Query("*") InputStream b); diff --git a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClientTest.java b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClientTest.java index 77b4255..e1e17b4 100644 --- a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClientTest.java +++ b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClientTest.java @@ -2824,7 +2824,7 @@ public class RestClientTest { .headers("Foo"); fail("Exception expected"); } catch (RuntimeException e) { - assertEquals("Invalid type passed to headers(Object...): java.lang.String", e.getLocalizedMessage()); + assertEquals("Invalid type passed to headers(): java.lang.String", e.getLocalizedMessage()); } } @@ -2837,7 +2837,7 @@ public class RestClientTest { .headerPairs("Foo"); fail("Exception expected"); } catch (RuntimeException e) { - assertEquals("Odd number of parameters passed into headerPairs(Object...)", e.getLocalizedMessage()); + assertEquals("Odd number of parameters passed into headerPairs()", e.getLocalizedMessage()); } } @@ -2992,7 +2992,7 @@ public class RestClientTest { .queries(BasicNameValuePair.of("Foo","bar"), "Baz"); fail(); } catch (Exception e) { - assertEquals("Invalid type passed to query(Object...): java.lang.String", e.getMessage()); + assertEquals("Invalid type passed to query(): java.lang.String", e.getMessage()); } } @@ -3033,6 +3033,83 @@ public class RestClientTest { } } + public static class I11 { + public String foo; + + I11 init() { + this.foo = "baz"; + return this; + } + } + + @Test + public void i11_query_request() throws Exception { + MockRestClient + .create(A.class) + .simpleJson() + .build() + .get("/echo") + .query("foo", "bar") + .run() + .assertBody().contains("GET /echo?foo=bar"); + MockRestClient + .create(A.class) + .simpleJson() + .build() + .get("/echo") + .query("foo", AList.of("bar","baz"), HttpPartSchema.T_ARRAY_PIPES) + .run() + .assertBody().contains("GET /echo?foo=bar%7Cbaz"); + MockRestClient + .create(A.class) + .simpleJson() + .query("foo","bar") + .build() + .get("/echo") + .query(EnumSet.of(AddFlag.PREPEND), "foo", "baz") + .run() + .assertBody().contains("GET /echo?foo=baz&foo=bar"); + MockRestClient + .create(A.class) + .simpleJson() + .query("foo","bar") + .build() + .get("/echo") + .query(EnumSet.of(AddFlag.PREPEND), "foo", AList.of("baz","qux"), HttpPartSchema.T_ARRAY_PIPES) + .run() + .assertBody().contains("GET /echo?foo=baz%7Cqux&foo=bar"); + MockRestClient + .create(A.class) + .simpleJson() + .query("foo","bar") + .build() + .get("/echo") + .queries(BasicNameValuePair.of("foo","baz"), NameValuePairs.of("foo","qux"), OMap.of("foo","quux")) + .run() + .assertBody().contains("GET /echo?foo=bar&foo=baz&foo=qux&foo=quux"); + MockRestClient + .create(A.class) + .simpleJson() + .query("foo","bar") + .build() + .get("/echo") + .queries(new I11().init()) + .run() + .assertBody().contains("GET /echo?foo=bar&foo=baz"); + try { + MockRestClient + .create(A.class) + .simpleJson() + .build() + .get("/echo") + .queries("foo=baz") + .run(); + fail(); + } catch (RestCallException e) { + assertEquals("Invalid type passed to queries(): java.lang.String", e.getMessage()); + } + } + //----------------------------------------------------------------------------------------------------------------- // Form data //----------------------------------------------------------------------------------------------------------------- @@ -3181,7 +3258,7 @@ public class RestClientTest { .formDatas(BasicNameValuePair.of("Foo","bar"), "Baz"); fail(); } catch (Exception e) { - assertEquals("Invalid type passed to formData(Object...): java.lang.String", e.getMessage()); + assertEquals("Invalid type passed to formData(): java.lang.String", e.getMessage()); } } @@ -6423,9 +6500,9 @@ public class RestClientTest { //----------------------------------------------------------------------------------------------------------------- public static class Q01 { - public int foo; + public int x; public Q01 init() { - foo = 1; + x = 1; return this; } @@ -6444,82 +6521,116 @@ public class RestClientTest { .get("/echo/{x}") .path("x", new Q01().init()) .run() - .assertBody().contains("HTTP GET /echo/foo=1") + .assertBody().contains("HTTP GET /echo/x=1") ; MockRestClient .create(A.class) .simpleJson() .build() .get("/echo/{x}") - .path("x", ()->new Q01().init()) + .path(BasicNameValuePair.of("x","foo")) .run() - .assertBody().contains("HTTP GET /echo/foo=1") + .assertBody().contains("HTTP GET /echo/foo") ; MockRestClient .create(A.class) .simpleJson() .build() - .get("/echo/*") - .path("/*", new Q01().init()) + .get("/echo/{x}") + .paths(BasicNameValuePair.of("x","foo")) .run() - .assertBody().contains("HTTP GET /echo/foo=1") + .assertBody().contains("HTTP GET /echo/foo") ; MockRestClient .create(A.class) .simpleJson() .build() - .get("/echo/*") - .path("/*", ()->new Q01().init()) + .get("/echo/{x}") + .paths(NameValuePairs.of("x","foo")) .run() - .assertBody().contains("HTTP GET /echo/foo=1") - ; - } - - @Test - public void q03_request_path_withSchema() throws Exception { - String[] a = new String[]{"foo","bar"}; - + .assertBody().contains("HTTP GET /echo/foo") + ; MockRestClient .create(A.class) .simpleJson() .build() .get("/echo/{x}") - .path("x", a, HttpPartSchema.T_ARRAY_PIPES) + .paths(OMap.of("x","foo")) .run() - .assertBody().contains("HTTP GET /echo/foo%7Cbar") + .assertBody().contains("HTTP GET /echo/foo") ; MockRestClient .create(A.class) .simpleJson() .build() .get("/echo/{x}") - .path("x", ()->a, HttpPartSchema.T_ARRAY_PIPES) + .paths(new Q01().init()) .run() - .assertBody().contains("HTTP GET /echo/foo%7Cbar") + .assertBody().contains("HTTP GET /echo/1") + ; + MockRestClient + .create(A.class) + .simpleJson() + .build() + .get("/echo/{x}") + .pathPairs("x", 1) + .run() + .assertBody().contains("HTTP GET /echo/1") + ; + MockRestClient + .create(A.class) + .simpleJson() + .build() + .get("/echo/*") + .path("/*", new Q01().init()) + .run() + .assertBody().contains("HTTP GET /echo/x=1") ; - } - - @Test - public void q04_request_path_invalid() throws Exception { try { MockRestClient .create(A.class) .simpleJson() .build() .get("/echo/{x}") - .path("y", "foo") + .paths("x") .run() - .assertBody().contains("HTTP GET /echo/foo%7Cbar") ; fail(); } catch (RestCallException e) { - assertEquals("Path variable {y} was not found in path.", e.getMessage()); + assertEquals("Invalid type passed to path(): java.lang.String", e.getMessage()); + } + try { + MockRestClient + .create(A.class) + .simpleJson() + .build() + .get("/echo/{x}") + .pathPairs("x") + .run() + ; + fail(); + } catch (RestCallException e) { + assertEquals("Odd number of parameters passed into pathPairs()", e.getMessage()); } } + @Test + public void q03_request_path_withSchema() throws Exception { + String[] a = new String[]{"foo","bar"}; + + MockRestClient + .create(A.class) + .simpleJson() + .build() + .get("/echo/{x}") + .path("x", a, HttpPartSchema.T_ARRAY_PIPES) + .run() + .assertBody().contains("HTTP GET /echo/foo%7Cbar") + ; + } @Test - public void q05_request_path_invalid() throws Exception { + public void q04_request_path_invalid() throws Exception { try { MockRestClient .create(A.class) diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClient.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClient.java index fa9a63f..1a76f8b 100644 --- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClient.java +++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClient.java @@ -15,7 +15,6 @@ package org.apache.juneau.rest.client2; import static org.apache.juneau.internal.StringUtils.*; import static org.apache.juneau.AddFlag.*; import static org.apache.juneau.httppart.HttpPartType.*; -import static org.apache.juneau.rest.client2.RestClientUtils.*; import static java.util.logging.Level.*; import static org.apache.juneau.internal.StateMachineState.*; import static java.lang.Character.*; @@ -56,6 +55,8 @@ import org.apache.juneau.assertions.*; import org.apache.juneau.collections.*; import org.apache.juneau.http.remote.RemoteReturn; import org.apache.juneau.http.*; +import org.apache.juneau.http.BasicNameValuePair; +import org.apache.juneau.http.header.BasicHeader; import org.apache.juneau.http.remote.*; import org.apache.juneau.httppart.*; import org.apache.juneau.httppart.bean.*; @@ -323,7 +324,6 @@ import org.apache.http.client.CookieStore; * <li class='jm'>{@link RestRequest#header(EnumSet,String,Object) header(EnumSet>AddFlag>,String,Object)} * <li class='jm'>{@link RestRequest#header(Header) header(Header)} * <li class='jm'>{@link RestRequest#header(NameValuePair) header(NameValuePair)} - * <li class='jm'>{@link RestRequest#header(EnumSet,Object) header(EnumSet>AddFlag>,Object)} * <li class='jm'>{@link RestRequest#headers(Object...) headers(Object...)} * <li class='jm'>{@link RestRequest#headers(EnumSet,Object...) headers(EnumSet>AddFlag>Object...)} * <li class='jm'>{@link RestRequest#headerPairs(Object...) headers(Object...)} @@ -413,7 +413,7 @@ import org.apache.http.client.CookieStore; * <li class='jm'>{@link RestRequest#query(String,Object) query(String,Object)} * <li class='jm'>{@link RestRequest#query(EnumSet,String,Object) query(EnumSet<AddFlag>,String,Object)} * <li class='jm'>{@link RestRequest#queries(Object...) queries(Object...)} - * <li class='jm'>{@link RestRequest#query(EnumSet,Object...) query(EnumSet<AddFlag>,Object...)} + * <li class='jm'>{@link RestRequest#queries(EnumSet,Object...) queries(EnumSet<AddFlag>,Object...)} * <li class='jm'>{@link RestRequest#queryPairs(Object...) queryPairs(Object...)} * <li class='jm'>{@link RestRequest#queryCustom(Object) queryCustom(Object)} * </ul> @@ -452,7 +452,7 @@ import org.apache.http.client.CookieStore; * <li class='jm'>{@link RestRequest#formData(String,Object) formData(String,Object)} * <li class='jm'>{@link RestRequest#formData(EnumSet,String,Object) formData(EnumSet<AddFlag>,String,Object)} * <li class='jm'>{@link RestRequest#formDatas(Object...) formDatas(Object...)} - * <li class='jm'>{@link RestRequest#formData(EnumSet,Object...) formData(EnumSet<AddFlag>,Object...)} + * <li class='jm'>{@link RestRequest#formDatas(EnumSet,Object...) formDatas(EnumSet<AddFlag>,Object...)} * <li class='jm'>{@link RestRequest#formDataPairs(Object...) formDataPairs(Object...)} * <li class='jm'>{@link RestRequest#formDataCustom(Object) formDataCustom(Object)} * </ul> @@ -1168,7 +1168,7 @@ public class RestClient extends BeanContext implements HttpClient, Closeable, Re * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#formData(String,Object) formData(String,Object)} * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#formData(EnumSet,String,Object) formData(EnumSet<AddFlag>,String,Object)} * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#formDatas(Object...) formDatas(Object...)} - * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#formData(EnumSet,Object...) formData(EnumSet<AddFlag>Object...)} + * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#formDatas(EnumSet,Object...) formDatas(EnumSet<AddFlag>Object...)} * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#formDataPairs(Object...) formDataPairs(Object...)} * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#formDataCustom(Object) formDataCustom(Object)} * </ul> @@ -1238,7 +1238,6 @@ public class RestClient extends BeanContext implements HttpClient, Closeable, Re * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#header(EnumSet,String,Object) header(EnumSet>AddFlag>,String,Object)} * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#header(Header) header(Header)} * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#header(NameValuePair) header(NameValuePair)} - * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#header(EnumSet,Object) header(EnumSet>AddFlag>,Object)} * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#headers(Object...) headers(Object...)} * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#headers(EnumSet,Object...) headers(EnumSet>AddFlag>,Object...)} * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#headerPairs(Object...) headerPairs(Object...)} @@ -1772,7 +1771,7 @@ public class RestClient extends BeanContext implements HttpClient, Closeable, Re * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#query(String,Object) query(String,Object)} * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#query(EnumSet,String,Object) query(EnumSet<AddFlag>,String,Object)} * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#queries(Object...) queries(Object...)} - * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#query(EnumSet,Object...) query(EnumSet<AddFlag>,Object...)} + * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#queries(EnumSet,Object...) queries(EnumSet<AddFlag>,Object...)} * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#queryPairs(Object...) queryPairs(Object...)} * <li class='jm'>{@link org.apache.juneau.rest.client2.RestRequest#queryCustom(Object) queryCustom(Object)} * </ul> @@ -1984,7 +1983,16 @@ public class RestClient extends BeanContext implements HttpClient, Closeable, Re HttpPartSerializerSession partSerializerSession = partSerializer.createPartSession(null); - Function<Object,Object> f = x -> x instanceof SerializedNameValuePair.Builder ? ((SerializedNameValuePair.Builder)x).serializer(partSerializerSession, false).build() : x; + Function<Object,Object> f = new Function<Object,Object>() { + @Override + public Object apply(Object x) { + if (x instanceof SerializedNameValuePair.Builder) + return ((SerializedNameValuePair.Builder)x).serializer(partSerializerSession, false).build(); + if (x instanceof SerializedHeader.Builder) + return ((SerializedHeader.Builder)x).serializer(partSerializerSession, false).build(); + return x; + } + }; this.headers = Collections.unmodifiableList( getListProperty(RESTCLIENT_headers, Object.class) @@ -2844,10 +2852,10 @@ public class RestClient extends BeanContext implements HttpClient, Closeable, Re req.header(toHeader(o)); for (Object o : query) - req.query(toQuery(o)); + req.query(toNameValuePair(o)); for (Object o : formData) - req.formData(toFormData(o)); + req.formData(toNameValuePair(o)); onInit(req); @@ -3005,16 +3013,16 @@ public class RestClient extends BeanContext implements HttpClient, Closeable, Re rc.parser(parser); for (RemoteMethodArg a : rmm.getPathArgs()) - rc.path(a.getName(), args[a.getIndex()], a.getSchema(), a.getSerializer(s)); + rc.pathArg(a.getName(), args[a.getIndex()], a.getSchema(), a.getSerializer(s)); for (RemoteMethodArg a : rmm.getQueryArgs()) - rc.query(a.isSkipIfEmpty() ? SKIP_IF_EMPTY_FLAGS : DEFAULT_FLAGS, a.getName(), args[a.getIndex()], a.getSchema(), a.getSerializer(s)); + rc.queryArg(a.isSkipIfEmpty() ? SKIP_IF_EMPTY_FLAGS : DEFAULT_FLAGS, a.getName(), args[a.getIndex()], a.getSchema(), a.getSerializer(s)); for (RemoteMethodArg a : rmm.getFormDataArgs()) - rc.formData(a.isSkipIfEmpty() ? SKIP_IF_EMPTY_FLAGS : DEFAULT_FLAGS, a.getName(), args[a.getIndex()], a.getSchema(), a.getSerializer(s)); + rc.formDataArg(a.isSkipIfEmpty() ? SKIP_IF_EMPTY_FLAGS : DEFAULT_FLAGS, a.getName(), args[a.getIndex()], a.getSchema(), a.getSerializer(s)); for (RemoteMethodArg a : rmm.getHeaderArgs()) - rc.header(a.isSkipIfEmpty() ? SKIP_IF_EMPTY_FLAGS : DEFAULT_FLAGS, a.getName(), args[a.getIndex()], a.getSchema(), a.getSerializer(s)); + rc.headerArg(a.isSkipIfEmpty() ? SKIP_IF_EMPTY_FLAGS : DEFAULT_FLAGS, a.getName(), args[a.getIndex()], a.getSchema(), a.getSerializer(s)); RemoteMethodArg ba = rmm.getBodyArg(); if (ba != null) @@ -3033,14 +3041,14 @@ public class RestClient extends BeanContext implements HttpClient, Closeable, Re HttpPartSchema schema = p.getSchema(); EnumSet<AddFlag> flags = schema.isSkipIfEmpty() ? SKIP_IF_EMPTY_FLAGS : DEFAULT_FLAGS; if (pt == PATH) - rc.path(pn, val, schema, p.getSerializer(s)); + rc.pathArg(pn, val, schema, p.getSerializer(s)); else if (val != null) { if (pt == QUERY) - rc.query(flags, pn, val, schema, ps); + rc.queryArg(flags, pn, val, schema, ps); else if (pt == FORMDATA) - rc.formData(flags, pn, val, schema, ps); + rc.formDataArg(flags, pn, val, schema, ps); else if (pt == HEADER) - rc.header(flags, pn, val, schema, ps); + rc.headerArg(flags, pn, val, schema, ps); else /* (pt == HttpPartType.BODY) */ rc.body(val, schema); } @@ -3693,6 +3701,22 @@ public class RestClient extends BeanContext implements HttpClient, Closeable, Re return (T)o; } + private static Header toHeader(Object o) { + if (o instanceof Header) + return (Header)o; + if (o instanceof Headerable) + return ((Headerable)o).asHeader(); + if (o instanceof NameValuePair) + return BasicHeader.of((NameValuePair)o); + return null; + } + + private static NameValuePair toNameValuePair(Object o) { + if (o instanceof NameValuePair) + return (NameValuePair)o; + return null; + } + @Override /* Context */ public OMap toMap() { return super.toMap() diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClientBuilder.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClientBuilder.java index 5bb4302..f9effa6 100644 --- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClientBuilder.java +++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClientBuilder.java @@ -48,6 +48,7 @@ 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.juneau.http.header.BasicHeader; import org.apache.http.protocol.*; import org.apache.juneau.*; import org.apache.juneau.annotation.*; @@ -1087,7 +1088,7 @@ public class RestClientBuilder extends BeanContextBuilder { */ @FluentSetter public RestClientBuilder header(String name, Object value, HttpPartSchema schema, HttpPartSerializer serializer) { - return appendTo(RESTCLIENT_headers, SerializedNameValuePair.create().name(name).value(value).type(HEADER).serializer(serializer).schema(schema)); + return headers(serializedHeader(name, value, serializer, schema)); } /** @@ -1123,7 +1124,7 @@ public class RestClientBuilder extends BeanContextBuilder { */ @FluentSetter public RestClientBuilder header(String name, Supplier<?> value, HttpPartSchema schema, HttpPartSerializer serializer) { - return appendTo(RESTCLIENT_headers, SerializedNameValuePair.create().name(name).value(value).type(HEADER).serializer(serializer).schema(schema)); + return headers(serializedHeader(name, value, serializer, schema)); } /** @@ -1155,7 +1156,7 @@ public class RestClientBuilder extends BeanContextBuilder { */ @FluentSetter public RestClientBuilder header(String name, Object value, HttpPartSchema schema) { - return appendTo(RESTCLIENT_headers, SerializedNameValuePair.create().name(name).value(value).type(HEADER).schema(schema)); + return headers(serializedHeader(name, value, null, schema)); } /** @@ -1187,7 +1188,7 @@ public class RestClientBuilder extends BeanContextBuilder { */ @FluentSetter public RestClientBuilder header(String name, Supplier<?> value, HttpPartSchema schema) { - return appendTo(RESTCLIENT_headers, SerializedNameValuePair.create().name(name).value(value).type(HEADER).schema(schema)); + return headers(serializedHeader(name, value, null, schema)); } /** @@ -1216,7 +1217,7 @@ public class RestClientBuilder extends BeanContextBuilder { */ @FluentSetter public RestClientBuilder header(String name, Object value) { - return header(name, value, null, null); + return headers(serializedHeader(name, value, null, null)); } /** @@ -1245,7 +1246,7 @@ public class RestClientBuilder extends BeanContextBuilder { */ @FluentSetter public RestClientBuilder header(String name, Supplier<?> value) { - return header(name, value, (HttpPartSchema)null, null); + return headers(serializedHeader(name, value, null, null)); } /** @@ -1264,7 +1265,7 @@ public class RestClientBuilder extends BeanContextBuilder { */ @FluentSetter public RestClientBuilder header(Header header) { - return appendTo(RESTCLIENT_headers, header); + return headers(header); } /** @@ -1283,7 +1284,7 @@ public class RestClientBuilder extends BeanContextBuilder { */ @FluentSetter public RestClientBuilder header(NameValuePair pair) { - return appendTo(RESTCLIENT_headers, pair); + return headers(pair); } /** @@ -1323,19 +1324,21 @@ public class RestClientBuilder extends BeanContextBuilder { @FluentSetter public RestClientBuilder headers(Object...headers) { for (Object h : headers) { - if (h instanceof Header) - header((Header)h); - else if (h instanceof NameValuePair) - header((NameValuePair)h); - else if (h instanceof Map) { - Map m = (Map)h; - for (Map.Entry e : (Set<Map.Entry>)m.entrySet()) - header(stringify(e.getKey()), e.getValue(), null, null); + if (h instanceof Header || h instanceof SerializedHeader.Builder || h instanceof SerializedNameValuePair.Builder) + appendTo(RESTCLIENT_headers, h); + else if (h instanceof Headerable) + appendTo(RESTCLIENT_headers, ((Headerable)h).asHeader()); + else if (h instanceof NameValuePair) { + NameValuePair p = (NameValuePair)h; + appendTo(RESTCLIENT_headers, new BasicHeader(p.getName(), p.getValue())); + } else if (h instanceof Map) { + for (Map.Entry e : toMap(h).entrySet()) + appendTo(RESTCLIENT_headers, serializedHeader(e.getKey(), e.getValue(), null, null)); } else if (h instanceof NameValuePairs) { for (NameValuePair p : (NameValuePairs)h) - header(p); + headers(p); } else if (h != null) { - throw new RuntimeException("Invalid type passed to headers(Object...): " + h.getClass().getName()); + throw new RuntimeException("Invalid type passed to headers(): " + h.getClass().getName()); } } return this; @@ -1363,9 +1366,9 @@ public class RestClientBuilder extends BeanContextBuilder { @FluentSetter public RestClientBuilder headerPairs(Object...pairs) { if (pairs.length % 2 != 0) - throw new RuntimeException("Odd number of parameters passed into headerPairs(Object...)"); + throw new RuntimeException("Odd number of parameters passed into headerPairs()"); for (int i = 0; i < pairs.length; i+=2) - header(stringify(pairs[i]), pairs[i+1]); + headers(serializedHeader(pairs[i], pairs[i+1], null, null)); return this; } @@ -1868,7 +1871,7 @@ public class RestClientBuilder extends BeanContextBuilder { */ @FluentSetter public RestClientBuilder query(String name, Object value, HttpPartSchema schema, HttpPartSerializer serializer) { - return appendTo(RESTCLIENT_query, SerializedNameValuePair.create().name(name).value(value).type(QUERY).serializer(serializer).schema(schema)); + return queries(serializedNameValuePair(name, value, QUERY, serializer, schema)); } /** @@ -1904,7 +1907,7 @@ public class RestClientBuilder extends BeanContextBuilder { */ @FluentSetter public RestClientBuilder query(String name, Supplier<?> value, HttpPartSchema schema, HttpPartSerializer serializer) { - return appendTo(RESTCLIENT_query, SerializedNameValuePair.create().name(name).value(value).type(QUERY).serializer(serializer).schema(schema)); + return queries(serializedNameValuePair(name, value, QUERY, serializer, schema)); } /** @@ -1936,7 +1939,7 @@ public class RestClientBuilder extends BeanContextBuilder { */ @FluentSetter public RestClientBuilder query(String name, Object value, HttpPartSchema schema) { - return appendTo(RESTCLIENT_query, SerializedNameValuePair.create().name(name).value(value).type(QUERY).schema(schema)); + return queries(serializedNameValuePair(name, value, QUERY, null, schema)); } /** @@ -1968,7 +1971,7 @@ public class RestClientBuilder extends BeanContextBuilder { */ @FluentSetter public RestClientBuilder query(String name, Supplier<?> value, HttpPartSchema schema) { - return appendTo(RESTCLIENT_query, SerializedNameValuePair.create().name(name).value(value).type(QUERY).schema(schema)); + return queries(serializedNameValuePair(name, value, QUERY, null, schema)); } /** @@ -1993,7 +1996,7 @@ public class RestClientBuilder extends BeanContextBuilder { */ @FluentSetter public RestClientBuilder query(String name, Object value) { - return query(name, value, null, null); + return queries(serializedNameValuePair(name, value, QUERY, null, null)); } /** @@ -2037,7 +2040,7 @@ public class RestClientBuilder extends BeanContextBuilder { */ @FluentSetter public RestClientBuilder query(String name, Supplier<?> value) { - return query(name, value, (HttpPartSchema)null, null); + return queries(serializedNameValuePair(name, value, QUERY, null, null)); } /** @@ -2076,17 +2079,16 @@ public class RestClientBuilder extends BeanContextBuilder { @FluentSetter public RestClientBuilder queries(Object...params) { for (Object p : params) { - if (p instanceof NameValuePair) { + if (p instanceof NameValuePair || p instanceof SerializedNameValuePair.Builder) { appendTo(RESTCLIENT_query, p); } else if (p instanceof Map) { - Map m = (Map)p; - for (Map.Entry e : (Set<Map.Entry>)m.entrySet()) - query(stringify(e.getKey()), e.getValue(), null, null); + for (Map.Entry e : toMap(p).entrySet()) + appendTo(RESTCLIENT_query, serializedNameValuePair(e.getKey(), e.getValue(), QUERY, null, null)); } else if (p instanceof NameValuePairs) { for (NameValuePair nvp : (NameValuePairs)p) - queries(nvp); + appendTo(RESTCLIENT_query, nvp); } else if (p != null) { - throw new RuntimeException("Invalid type passed to query(Object...): " + p.getClass().getName()); + throw new RuntimeException("Invalid type passed to query(): " + p.getClass().getName()); } } return this; @@ -2116,7 +2118,7 @@ public class RestClientBuilder extends BeanContextBuilder { if (pairs.length % 2 != 0) throw new RuntimeException("Odd number of parameters passed into queryPairs(Object...)"); for (int i = 0; i < pairs.length; i+=2) - query(stringify(pairs[i]), pairs[i+1]); + queries(serializedNameValuePair(pairs[i], pairs[i+1], QUERY, null, null)); return this; } @@ -2157,7 +2159,7 @@ public class RestClientBuilder extends BeanContextBuilder { */ @FluentSetter public RestClientBuilder formData(String name, Object value, HttpPartSchema schema, HttpPartSerializer serializer) { - return appendTo(RESTCLIENT_formData, SerializedNameValuePair.create().name(name).value(value).type(FORMDATA).serializer(serializer).schema(schema)); + return formDatas(serializedNameValuePair(name, value, FORMDATA, serializer, schema)); } /** @@ -2193,7 +2195,7 @@ public class RestClientBuilder extends BeanContextBuilder { */ @FluentSetter public RestClientBuilder formData(String name, Supplier<?> value, HttpPartSchema schema, HttpPartSerializer serializer) { - return appendTo(RESTCLIENT_formData, SerializedNameValuePair.create().name(name).value(value).type(FORMDATA).serializer(serializer).schema(schema)); + return formDatas(serializedNameValuePair(name, value, FORMDATA, serializer, schema)); } /** @@ -2225,7 +2227,7 @@ public class RestClientBuilder extends BeanContextBuilder { */ @FluentSetter public RestClientBuilder formData(String name, Object value, HttpPartSchema schema) { - return appendTo(RESTCLIENT_formData, SerializedNameValuePair.create().name(name).value(value).type(FORMDATA).schema(schema)); + return formDatas(serializedNameValuePair(name, value, FORMDATA, null, schema)); } /** @@ -2257,7 +2259,7 @@ public class RestClientBuilder extends BeanContextBuilder { */ @FluentSetter public RestClientBuilder formData(String name, Supplier<?> value, HttpPartSchema schema) { - return appendTo(RESTCLIENT_formData, SerializedNameValuePair.create().name(name).value(value).type(FORMDATA).schema(schema)); + return formDatas(serializedNameValuePair(name, value, FORMDATA, null, schema)); } /** @@ -2282,7 +2284,7 @@ public class RestClientBuilder extends BeanContextBuilder { */ @FluentSetter public RestClientBuilder formData(String name, Object value) { - return formData(name, value, null, null); + return formDatas(serializedNameValuePair(name, value, FORMDATA, null, null)); } /** @@ -2326,7 +2328,7 @@ public class RestClientBuilder extends BeanContextBuilder { */ @FluentSetter public RestClientBuilder formData(String name, Supplier<?> value) { - return formData(name, value, (HttpPartSchema)null, null); + return formDatas(serializedNameValuePair(name, value, FORMDATA, null, null)); } /** @@ -2361,21 +2363,19 @@ public class RestClientBuilder extends BeanContextBuilder { * @param params The form-data parameter. * @return This object (for method chaining). */ - @SuppressWarnings("rawtypes") @FluentSetter public RestClientBuilder formDatas(Object...params) { for (Object p : params) { - if (p instanceof NameValuePair) { + if (p instanceof NameValuePair || p instanceof SerializedNameValuePair.Builder) { appendTo(RESTCLIENT_formData, p); } else if (p instanceof Map) { - Map m = (Map)p; - for (Map.Entry e : (Set<Map.Entry>)m.entrySet()) - formData(stringify(e.getKey()), e.getValue(), null, null); + for (Map.Entry<Object,Object> e : toMap(p).entrySet()) + appendTo(RESTCLIENT_formData, serializedNameValuePair(e.getKey(), e.getValue(), FORMDATA, null, null)); } else if (p instanceof NameValuePairs) { for (NameValuePair nvp : (NameValuePairs)p) - formDatas(nvp); + appendTo(RESTCLIENT_formData, nvp); } else if (p != null) { - throw new RuntimeException("Invalid type passed to formData(Object...): " + p.getClass().getName()); + throw new RuntimeException("Invalid type passed to formData(): " + p.getClass().getName()); } } return this; @@ -2405,7 +2405,7 @@ public class RestClientBuilder extends BeanContextBuilder { if (pairs.length % 2 != 0) throw new RuntimeException("Odd number of parameters passed into formDataPairs(Object...)"); for (int i = 0; i < pairs.length; i+=2) - formData(stringify(pairs[i]), pairs[i+1]); + formDatas(serializedNameValuePair(pairs[i], pairs[i+1], FORMDATA, null, null)); return this; } @@ -5808,4 +5808,21 @@ public class RestClientBuilder extends BeanContextBuilder { httpClientBuilder.evictIdleConnections(maxIdleTime, maxIdleTimeUnit); return this; } + + //------------------------------------------------------------------------------------------------------------------ + // Utility methods. + //------------------------------------------------------------------------------------------------------------------ + + @SuppressWarnings("unchecked") + private static Map<Object,Object> toMap(Object o) { + return (Map<Object,Object>)o; + } + + private static SerializedNameValuePair.Builder serializedNameValuePair(Object key, Object value, HttpPartType type, HttpPartSerializer serializer, HttpPartSchema schema) { + return SerializedNameValuePair.create().name(stringify(key)).value(value).type(type).serializer(serializer).schema(schema); + } + + private static SerializedHeader.Builder serializedHeader(Object key, Object value, HttpPartSerializer serializer, HttpPartSchema schema) { + return SerializedHeader.create().name(stringify(key)).value(value).serializer(serializer).schema(schema); + } } diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClientUtils.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClientUtils.java deleted file mode 100644 index 56593e2..0000000 --- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClientUtils.java +++ /dev/null @@ -1,103 +0,0 @@ -// *************************************************************************************************************************** -// * 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.client2; - -import static org.apache.juneau.AddFlag.*; -import static org.apache.juneau.httppart.HttpPartType.*; -import static org.apache.juneau.internal.StringUtils.*; - -import java.util.*; - -import org.apache.http.*; -import org.apache.http.message.BasicHeader; -import org.apache.juneau.*; -import org.apache.juneau.http.*; -import org.apache.juneau.httppart.*; - -/** - * Static utility methods shared by mutiple classes. - */ -class RestClientUtils { - - static Header toHeader(Object o) { - if (o instanceof Header) - return (Header)o; - if (o instanceof NameValuePair) { - NameValuePair p = (NameValuePair)o; - return new BasicHeader(p.getName(), p.getValue()); - } - return null; - } - - static NameValuePair toQuery(Object o) { - if (o instanceof NameValuePair) - return (NameValuePair)o; - return null; - } - - static NameValuePair toFormData(Object o) { - if (o instanceof NameValuePair) - return (NameValuePair)o; - return null; - } - - static List<Header> toHeaders(NameValuePair...pairs) { - List<Header> l = new ArrayList<>(); - for (NameValuePair p : pairs) - l.add(toHeader(p)); - return l; - } - - static List<Header> toHeaders(NameValuePairs pairs) { - List<Header> l = new ArrayList<>(); - for (NameValuePair p : pairs) - l.add(toHeader(p)); - return l; - } - - static Header toHeader(EnumSet<AddFlag> flags, String name, Object value, HttpPartSerializerSession serializer, HttpPartSchema schema) { - return new SerializedHeader(name, value, serializer, schema, flags.contains(SKIP_IF_EMPTY)); - } - - static NameValuePair toQuery(EnumSet<AddFlag> flags, String name, Object value, HttpPartSerializerSession serializer, HttpPartSchema schema) { - return new SerializedNameValuePair(name, value, QUERY, serializer, schema, flags.contains(SKIP_IF_EMPTY)); - } - - static NameValuePair toFormData(EnumSet<AddFlag> flags, String name, Object value, HttpPartSerializerSession serializer, HttpPartSchema schema) { - return new SerializedNameValuePair(name, value, FORMDATA, serializer, schema, flags.contains(SKIP_IF_EMPTY)); - } - - @SuppressWarnings("rawtypes") - static List<Header> toHeaders(EnumSet<AddFlag> flags, Map headers, HttpPartSerializerSession serializer, HttpPartSchema schema) { - List<Header> l = new ArrayList<>(); - for (Map.Entry e : (Set<Map.Entry>)headers.entrySet()) - l.add(new SerializedHeader(stringify(e.getKey()), e.getValue(), serializer, null, flags.contains(SKIP_IF_EMPTY))); - return l; - } - - @SuppressWarnings("rawtypes") - static List<NameValuePair> toQuery(EnumSet<AddFlag> flags, Map params, HttpPartSerializerSession serializer, HttpPartSchema schema) { - List<NameValuePair> l = new ArrayList<>(); - for (Map.Entry e : (Set<Map.Entry>)params.entrySet()) - l.add(new SerializedNameValuePair(stringify(e.getKey()), e.getValue(), QUERY, serializer, null, flags.contains(SKIP_IF_EMPTY))); - return l; - } - - @SuppressWarnings("rawtypes") - static List<NameValuePair> toFormData(EnumSet<AddFlag> flags, Map params, HttpPartSerializerSession serializer, HttpPartSchema schema) { - List<NameValuePair> l = new ArrayList<>(); - for (Map.Entry e : (Set<Map.Entry>)params.entrySet()) - l.add(new SerializedNameValuePair(stringify(e.getKey()), e.getValue(), FORMDATA, serializer, null, flags.contains(SKIP_IF_EMPTY))); - return l; - } -} diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestRequest.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestRequest.java index b834687..08380bc 100644 --- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestRequest.java +++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestRequest.java @@ -15,7 +15,6 @@ package org.apache.juneau.rest.client2; import static org.apache.juneau.internal.StringUtils.*; import static org.apache.juneau.AddFlag.*; import static org.apache.juneau.httppart.HttpPartType.*; -import static org.apache.juneau.rest.client2.RestClientUtils.*; import java.io.*; import java.net.*; @@ -33,13 +32,13 @@ import org.apache.http.client.utils.*; import org.apache.http.concurrent.*; import org.apache.http.entity.*; import org.apache.http.entity.ContentType; +import org.apache.juneau.http.header.BasicHeader; import org.apache.http.params.*; import org.apache.http.protocol.*; import org.apache.juneau.*; import org.apache.juneau.collections.*; import org.apache.juneau.html.*; import org.apache.juneau.http.*; -import org.apache.juneau.http.header.*; import org.apache.juneau.httppart.*; import org.apache.juneau.internal.*; import org.apache.juneau.json.*; @@ -47,7 +46,6 @@ import org.apache.juneau.msgpack.*; import org.apache.juneau.oapi.*; import org.apache.juneau.parser.*; import org.apache.juneau.plaintext.*; -import org.apache.juneau.reflect.*; import org.apache.juneau.serializer.*; import org.apache.juneau.uon.*; import org.apache.juneau.urlencoding.*; @@ -863,6 +861,7 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Sets path to "/bar".</jc> * client * .get(<js>"/{foo}"</js>) * .path(<js>"foo"</js>, <js>"bar"</js>) @@ -872,15 +871,14 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * @param name The parameter name. * @param value The parameter value. * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. + * <li>Value can be any POJO. + * <li>Value converted to a string using the configured part serializer. * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ public RestRequest path(String name, Object value) throws RestCallException { - return path(name, value, null, partSerializer); + return paths(serializedNameValuePair(name, value, PATH, partSerializer, null, null)); } /** @@ -888,6 +886,7 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Sets path to "/bar".</jc> * client * .get(<js>"/{foo}"</js>) * .path(BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>, <js>"bar"</js>)) @@ -899,7 +898,7 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * @throws RestCallException Invalid input. */ public RestRequest path(NameValuePair pair) throws RestCallException { - return innerPath(pair); + return paths(pair); } /** @@ -907,90 +906,28 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Sets path to "/bar|baz".</jc> * client * .get(<js>"/{foo}"</js>) - * .path(<js>"foo"</js>, ()-><js>"bar"</js>) + * .path( + * <js>"foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), + * HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf> + * ) * .run(); * </p> * - * @param name - * The parameter name. - * <br>Can also be <js>"/*"</js> to replace the remainder in a path of the form <js>"/foo/*"</js>. - * @param value The parameter value supplier. - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * @return This object (for method chaining). - * @throws RestCallException Invalid input. - */ - public RestRequest path(String name, Supplier<?> value) throws RestCallException { - return path(name, value, null, partSerializer); - } - - /** - * Replaces a path parameter of the form <js>"{name}"</js> in the URL. - * - * <p> - * The optional schema allows for specifying how part should be serialized (as a pipe-delimited list for example). - * - * <h5 class='section'>Example:</h5> - * <p class='bcode w800'> - * <jc>// Creates path "/bar|baz"</jc> - * client - * .get(<js>"/{foo}"</js>) - * .path(<js>"foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf>) - * .run(); - * </p> - * - * @param name - * The parameter name. - * <br>Can also be <js>"/*"</js> to replace the remainder in a path of the form <js>"/foo/*"</js>. + * @param name The parameter name. * @param value The parameter value. * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. + * <li>Value can be any POJO. + * <li>Value converted to a string using the configured part serializer. * </ul> * @param schema The part schema. Can be <jk>null</jk>. * @return This object (for method chaining). * @throws RestCallException Invalid input. */ public RestRequest path(String name, Object value, HttpPartSchema schema) throws RestCallException { - return path(name, value, schema, partSerializer); - } - - /** - * Replaces a path parameter of the form <js>"{name}"</js> in the URL. - * - * <p> - * The optional schema allows for specifying how part should be serialized (as a pipe-delimited list for example). - * - * <h5 class='section'>Example:</h5> - * <p class='bcode w800'> - * <jc>// Creates path "/bar|baz"</jc> - * client - * .get(<js>"/{foo}"</js>) - * .path(<js>"foo"</js>, ()->AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf>) - * .run(); - * </p> - * - * @param name - * The parameter name. - * <br>Can also be <js>"/*"</js> to replace the remainder in a path of the form <js>"/foo/*"</js>. - * @param value The parameter value supplier. - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * @param schema The part schema. Can be <jk>null</jk>. - * @return This object (for method chaining). - * @throws RestCallException Invalid input. - */ - public RestRequest path(String name, Supplier<?> value, HttpPartSchema schema) throws RestCallException { - return path(name, value, schema, partSerializer); + return paths(serializedNameValuePair(name, value, PATH, partSerializer, schema, null)); } /** @@ -998,27 +935,21 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Sets path to "/baz/qux".</jc> * client - * .get(<jsf>URL</jsf>) - * .path(BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>, <js>"bar"</js>)) + * .get(<js>"/{foo}/{bar}") + * .paths( + * BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>, <js>"baz"</js>), + * AMap.<jsm>of</jsm>(<js>"bar"</js>, <js>"qux"</js>) + * ) * .run(); * </p> * - * @param params The parameters to set. + * @param params The path parameters to set. * <br>Can be any of the following types: * <ul> - * <li>{@link NameValuePair} - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li><jk>null</jk> - Will be a no-op. + * <li>{@link Map} / {@link OMap} / bean - Converted to key/value pairs using part serializer. + * <li>{@link NameValuePair} / {@link NameValuePairs} - Converted to key/value pairs directly. * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. @@ -1032,12 +963,11 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur for (NameValuePair p : (NameValuePairs)o) innerPath(p); } else if (o instanceof Map) { - Map m = (Map)o; - for (Map.Entry e : (Set<Map.Entry>)m.entrySet()) - innerPath(new SerializedNameValuePair(stringify(e.getKey()), e.getValue(), PATH, partSerializer, null, false)); + for (Map.Entry e : toMap(o).entrySet()) + innerPath(serializedNameValuePair(e.getKey(), e.getValue(), PATH, partSerializer, null, null)); } else if (isBean(o)) { for (Map.Entry<String,Object> e : toBeanMap(o).entrySet()) - innerPath(new SerializedNameValuePair(stringify(e.getKey()), e.getValue(), PATH, partSerializer, null, false)); + innerPath(serializedNameValuePair(e.getKey(), e.getValue(), PATH, partSerializer, null, null)); } else { throw new RestCallException("Invalid type passed to path(): " + o.getClass().getName()); } @@ -1050,9 +980,13 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Sets path to "/baz/qux".</jc> * client * .get(<js>"/{foo}/{bar}"</js>) - * .path(<js>"foo"</js>,<js>"val1"</js>,<js>"bar"</js>,<js>"val2"</js>) + * .pathPairs( + * <js>"foo"</js>,<js>"baz"</js>, + * <js>"bar"</js>,<js>"qux"</js> + * ) * .run(); * </p> * @@ -1060,37 +994,34 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * <ul> * <li>Values can be any POJO. * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ public RestRequest pathPairs(Object...pairs) throws RestCallException { if (pairs.length % 2 != 0) - throw new RestCallException("Odd number of parameters passed into path(Object...)"); + throw new RestCallException("Odd number of parameters passed into pathPairs()"); for (int i = 0; i < pairs.length; i+=2) - paths(new SerializedNameValuePair(stringify(pairs[i]), pairs[i+1], PATH, partSerializer, null, false)); + paths(serializedNameValuePair(pairs[i], pairs[i+1], PATH, partSerializer, null, null)); return this; } - @SuppressWarnings("unchecked") - RestRequest path(String name, Object value, HttpPartSchema schema, HttpPartSerializerSession serializer) throws RestCallException { + RestRequest pathArg(String name, Object value, HttpPartSchema schema, HttpPartSerializerSession serializer) throws RestCallException { serializer = (serializer == null ? partSerializer : serializer); boolean isMulti = isEmpty(name) || "*".equals(name) || value instanceof NameValuePairs; - if (! isMulti) { - innerPath(new SerializedNameValuePair(name, value, PATH, serializer, schema, false)); - } else if (value instanceof NameValuePairs) { + + if (! isMulti) + return innerPath(serializedNameValuePair(name, value, PATH, serializer, schema, null)); + + if (value instanceof NameValuePairs) { for (NameValuePair p : (NameValuePairs)value) innerPath(p); } else if (value instanceof Map) { - for (Map.Entry<String,Object> p : ((Map<String,Object>) value).entrySet()) { - String n = p.getKey(); - Object v = p.getValue(); - HttpPartSchema s = schema == null ? null : schema.getProperty(n); - innerPath(new SerializedNameValuePair(n, v, PATH, serializer, s, false)); - } + for (Map.Entry<Object,Object> p : toMap(value).entrySet()) + innerPath(serializedNameValuePair(p.getKey(), p.getValue(), PATH, serializer, schema, null)); } else if (isBean(value)) { - return path(name, toBeanMap(value), schema, serializer); + for (Map.Entry<String,Object> p : toBeanMap(value).entrySet()) + innerPath(serializedNameValuePair(p.getKey(), p.getValue(), PATH, serializer, schema, null)); } else if (value != null) { throw new RestCallException("Invalid name ''{0}'' passed to path(name,value) for data type ''{1}''", name, className(value)); } @@ -1119,6 +1050,19 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur /** * Sets a query parameter on the URI. * + * <h5 class='section'>Example:</h5> + * <p class='bcode w800'> + * <jc>// Adds query parameter "foo=bar|baz".</jc> + * client + * .get(<jsf>URL</jsf>) + * .query( + * EnumSet.<jsm>of</jsm>(<jsf>APPEND</jsf>,<jsf>SKIP_IF_EMPTY</jsf>), + * <js>"foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), + * HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf> + * ) + * .run(); + * </p> + * * @param flags Instructions on how to add this parameter. * <ul> * <li>{@link AddFlag#APPEND APPEND} (default) - Append to end. @@ -1127,34 +1071,10 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * <li>{@link AddFlag#SKIP_IF_EMPTY} - Don't add if value is an empty string. * </ul> * @param name The parameter name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of parameters. - * </ul> * @param value The parameter value. * <ul> - * <li>For single value parameters: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value parameters: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li>{@link Reader} / {@link InputStream} / {@link CharSequence} - * <ul> - * <li>Sets the entire query string to the contents of the input. - * </ul> - * </ul> + * <li>Value can be any POJO. + * <li>Value converted to a string using the configured part serializer. * </ul> * @param schema The schema object that defines the format of the output. * <ul> @@ -1165,59 +1085,7 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * @throws RestCallException Invalid input. */ public RestRequest query(EnumSet<AddFlag> flags, String name, Object value, HttpPartSchema schema) throws RestCallException { - return query(flags, name, value, schema, partSerializer); - } - - /** - * Sets a query parameter on the URI. - * - * @param flags Instructions on how to add this parameter. - * <ul> - * <li>{@link AddFlag#APPEND APPEND} (default) - Append to end. - * <li>{@link AddFlag#PREPEND PREPEND} - Prepend to beginning. - * <li>{@link AddFlag#REPLACE REPLACE} - Delete any existing with same name and append to end. - * <li>{@link AddFlag#SKIP_IF_EMPTY} - Don't add if value is an empty string. - * </ul> - * @param name The parameter name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of parameters. - * </ul> - * @param value The parameter value supplier. - * <ul> - * <li>For single value parameters: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value parameters: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li>{@link Reader} / {@link InputStream} / {@link CharSequence} - * <ul> - * <li>Sets the entire query string to the contents of the input. - * </ul> - * </ul> - * </ul> - * @param schema The schema object that defines the format of the output. - * <ul> - * <li>If <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. - * <li>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}). - * </ul> - * @return This object (for method chaining). - * @throws RestCallException Invalid input. - */ - public RestRequest query(EnumSet<AddFlag> flags, String name, Supplier<?> value, HttpPartSchema schema) throws RestCallException { - return query(flags, name, value, schema, partSerializer); + return queries(flags, serializedNameValuePair(name, value, QUERY, partSerializer, schema, null)); } /** @@ -1225,6 +1093,7 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Adds query parameter "foo=bar".</jc> * client * .get(<jsf>URL</jsf>) * .query(<js>"foo"</js>, <js>"bar"</js>) @@ -1232,40 +1101,16 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * </p> * * @param name The parameter name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of parameters. - * </ul> * @param value The parameter value. * <ul> - * <li>For single value parameters: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value parameters: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li>{@link Reader} / {@link InputStream} / {@link CharSequence} - * <ul> - * <li>Sets the entire query string to the contents of the input. - * </ul> - * </ul> + * <li>Value can be any POJO. + * <li>Value converted to a string using the configured part serializer. * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ public RestRequest query(String name, Object value) throws RestCallException { - return query(DEFAULT_FLAGS, name, value, null, partSerializer); + return queries(serializedNameValuePair(name, value, QUERY, partSerializer, null, null)); } /** @@ -1273,6 +1118,7 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Adds query parameter "foo=bar".</jc> * client * .get(<jsf>URL</jsf>) * .query(BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>, <js>"bar"</js>)) @@ -1290,54 +1136,6 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur /** * Adds a query parameter to the URI. * - * <h5 class='section'>Example:</h5> - * <p class='bcode w800'> - * client - * .get(<jsf>URL</jsf>) - * .query(<js>"foo"</js>, ()-><js>"bar"</js>) - * .run(); - * </p> - * - * @param name The parameter name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of parameters. - * </ul> - * @param value The parameter value. - * <ul> - * <li>For single value parameters: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value parameters: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li>{@link Reader} / {@link InputStream} / {@link CharSequence} - * <ul> - * <li>Sets the entire query string to the contents of the input. - * </ul> - * </ul> - * </ul> - * @return This object (for method chaining). - * @throws RestCallException Invalid input. - */ - public RestRequest query(String name, Supplier<?> value) throws RestCallException { - return query(DEFAULT_FLAGS, name, value, null, partSerializer); - } - - /** - * Adds a query parameter to the URI. - * * <p> * The optional schema allows for specifying how part should be serialized (as a pipe-delimited list for example). * @@ -1346,109 +1144,39 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * <jc>// Creates query parameter "foo=bar|baz"</jc> * client * .get(<jsf>URL</jsf>) - * .query(<js>"foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf>) + * .query( + * <js>"foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), + * HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf> + * ) * .run(); * </p> * * @param name The parameter name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of parameters. - * </ul> * @param value The parameter value. * <ul> - * <li>For single value parameters: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value parameters: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li>{@link Reader} / {@link InputStream} / {@link CharSequence} - * <ul> - * <li>Sets the entire query string to the contents of the input. - * </ul> - * </ul> + * <li>Value can be any POJO. + * <li>Value converted to a string using the configured part serializer. * </ul> * @param schema The HTTP part schema. Can be <jk>null</jk>. * @return This object (for method chaining). * @throws RestCallException Invalid input. */ public RestRequest query(String name, Object value, HttpPartSchema schema) throws RestCallException { - return query(DEFAULT_FLAGS, name, value, schema, partSerializer); + return queries(serializedNameValuePair(name, value, QUERY, partSerializer, schema, null)); } /** * Adds a query parameter to the URI. * - * <p> - * The optional schema allows for specifying how part should be serialized (as a pipe-delimited list for example). - * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> - * <jc>// Creates query parameter "foo=bar|baz"</jc> + * <jc>// Adds query parameter "foo=bar".</jc> * client * .get(<jsf>URL</jsf>) - * .query(<js>"foo"</js>, ()->AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf>) - * .run(); - * </p> - * - * @param name The parameter name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of parameters. - * </ul> - * @param value The parameter value. - * <ul> - * <li>For single value parameters: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value parameters: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li>{@link Reader} / {@link InputStream} / {@link CharSequence} - * <ul> - * <li>Sets the entire query string to the contents of the input. - * </ul> - * </ul> - * </ul> - * @param schema The HTTP part schema. Can be <jk>null</jk>. - * @return This object (for method chaining). - * @throws RestCallException Invalid input. - */ - public RestRequest query(String name, Supplier<?> value, HttpPartSchema schema) throws RestCallException { - return query(DEFAULT_FLAGS, name, value, schema, partSerializer); - } - - /** - * Adds a query parameter to the URI. - * - * <h5 class='section'>Example:</h5> - * <p class='bcode w800'> - * client - * .get(<jsf>URL</jsf>) - * .query(<js>"foo"</js>, <js>"bar"</js>) + * .query( + * EnumSet.<jsm>of</jsm>(<jsf>APPEND</jsf>,<jsf>SKIP_IF_EMPTY</jsf>), + * <js>"foo"</js>, <js>"bar"</js> + * ) * .run(); * </p> * @@ -1460,95 +1188,16 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * <li>{@link AddFlag#SKIP_IF_EMPTY} - Don't add if value is an empty string. * </ul> * @param name The parameter name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of parameters. - * </ul> * @param value The parameter value. * <ul> - * <li>For single value parameters: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value parameters: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li>{@link Reader} / {@link InputStream} / {@link CharSequence} - * <ul> - * <li>Sets the entire query string to the contents of the input. - * </ul> - * </ul> + * <li>Value can be any POJO. + * <li>Value converted to a string using the configured part serializer. * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ public RestRequest query(EnumSet<AddFlag> flags, String name, Object value) throws RestCallException { - return query(flags, name, value, null, partSerializer); - } - - /** - * Adds a query parameter to the URI. - * - * <h5 class='section'>Example:</h5> - * <p class='bcode w800'> - * client - * .get(<jsf>URL</jsf>) - * .query(<js>"foo"</js>, ()-><js>"bar"</js>) - * .run(); - * </p> - * - * @param flags Instructions on how to add this parameter. - * <ul> - * <li>{@link AddFlag#APPEND APPEND} (default) - Append to end. - * <li>{@link AddFlag#PREPEND PREPEND} - Prepend to beginning. - * <li>{@link AddFlag#REPLACE REPLACE} - Delete any existing with same name and append to end. - * <li>{@link AddFlag#SKIP_IF_EMPTY} - Don't add if value is an empty string. - * </ul> - * @param name The parameter name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of parameters. - * </ul> - * @param value The parameter value supplier. - * <ul> - * <li>For single value parameters: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value parameters: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li>{@link Reader} / {@link InputStream} / {@link CharSequence} - * <ul> - * <li>Sets the entire query string to the contents of the input. - * </ul> - * </ul> - * </ul> - * @return This object (for method chaining). - * @throws RestCallException Invalid input. - */ - public RestRequest query(EnumSet<AddFlag> flags, String name, Supplier<?> value) throws RestCallException { - return query(flags, name, value, null, partSerializer); + return queries(flags, serializedNameValuePair(name, value, QUERY, partSerializer, null, null)); } /** @@ -1556,33 +1205,27 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Adds query parameters "foo=bar&baz=qux".</jc> * client * .get(<jsf>URL</jsf>) - * .query(BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>, <js>"bar"</js>)) + * .queries( + * BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>), + * AMap.<jsm>of</jsm>(<js>"baz"<j/s>,<js>"qux"</js>) + * ) * .run(); * </p> * * @param params The parameters to set. * <br>Can be any of the following types: * <ul> - * <li>{@link NameValuePair} - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li><jk>null</jk> - Will be a no-op. + * <li>{@link Map} / {@link OMap} / bean - Converted to key/value pairs using part serializer. + * <li>{@link NameValuePair} / {@link NameValuePairs} - Converted to key/value pairs directly. * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ public RestRequest queries(Object...params) throws RestCallException { - return query(DEFAULT_FLAGS, params); + return queries(DEFAULT_FLAGS, params); } /** @@ -1590,9 +1233,14 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Adds query parameters "foo=bar&baz=qux".</jc> * client * .get(<jsf>URL</jsf>) - * .query(EnumSet.<jsm>of</jsm>(<jsf>REPLACE</jsf>,<jsf>SKIP_IF_EMPTY</jsf>),BasicNameValuePair.<jsm>of</jsm>(<js>"Foo"</js>, <js>"bar"</js>)) + * .queries( + * EnumSet.<jsm>of</jsm>(<jsf>APPEND</jsf>,<jsf>SKIP_IF_EMPTY</jsf>), + * BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>), + * AMap.<jsm>of</jsm>(<js>"baz"<j/s>,<js>"qux"</js>) + * ) * .run(); * </p> * @@ -1606,42 +1254,27 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * @param params The parameters to set. * <br>Can be any of the following types: * <ul> - * <li>{@link NameValuePair} - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li><jk>null</jk> - Will be a no-op. + * <li>{@link Map} / {@link OMap} / bean - Converted to key/value pairs using part serializer. + * <li>{@link NameValuePair} / {@link NameValuePairs} - Converted to key/value pairs directly. * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ - @SuppressWarnings("rawtypes") - public RestRequest query(EnumSet<AddFlag> flags, Object...params) throws RestCallException { + public RestRequest queries(EnumSet<AddFlag> flags, Object...params) throws RestCallException { List<NameValuePair> l = new ArrayList<>(); - boolean skipIfEmpty = flags.contains(SKIP_IF_EMPTY); for (Object o : params) { if (o instanceof NameValuePair) { l.add((NameValuePair)o); } else if (o instanceof NameValuePairs) { l.addAll((NameValuePairs)o); } else if (o instanceof Map) { - Map m = (Map)o; - for (Map.Entry e : (Set<Map.Entry>)m.entrySet()) - l.add(new SerializedNameValuePair(stringify(e.getKey()), e.getValue(), QUERY, partSerializer, null, skipIfEmpty)); + for (Map.Entry<Object,Object> e : toMap(o).entrySet()) + l.add(serializedNameValuePair(e.getKey(), e.getValue(), QUERY, partSerializer, null, null)); } else if (isBean(o)) { for (Map.Entry<String,Object> e : toBeanMap(o).entrySet()) - l.add(new SerializedNameValuePair(stringify(e.getKey()), e.getValue(), QUERY, partSerializer, null, skipIfEmpty)); - } else if (o instanceof Reader || o instanceof InputStream || o instanceof CharSequence) { - queryCustom(o); + l.add(serializedNameValuePair(e.getKey(), e.getValue(), QUERY, partSerializer, null, null)); } else { - throw new RestCallException("Invalid type passed to query(): " + o.getClass().getName()); + throw new RestCallException("Invalid type passed to queries(): " + o.getClass().getName()); } } return innerQuery(flags, l); @@ -1652,37 +1285,38 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Adds query parameters "foo=bar&baz=qux".</jc> * client * .get(<jsf>URL</jsf>) - * .queryPairs(<js>"key1"</js>,<js>"val1"</js>,<js>"key2"</js>,<js>"val2"</js>) + * .queryPairs(<js>"foo"</js>,<js>"bar"</js>,<js>"baz"</js>,<js>"qux"</js>) * .run(); * </p> * - * @param pairs The query key/value pairs. + * @param pairs The query key/value pairs. * <ul> * <li>Values can be any POJO. * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ public RestRequest queryPairs(Object...pairs) throws RestCallException { if (pairs.length % 2 != 0) - throw new RestCallException("Odd number of parameters passed into query(Object...)"); + throw new RestCallException("Odd number of parameters passed into queryPairs()"); for (int i = 0; i < pairs.length; i+=2) - queries(new SerializedNameValuePair(stringify(pairs[i]), pairs[i+1], QUERY, partSerializer, null, false)); + queries(serializedNameValuePair(pairs[i], pairs[i+1], QUERY, partSerializer, null, null)); return this; } /** - * Adds form-data parameters as the entire body of the request. + * Adds a free-form custom query. * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Adds query parameter "foo=bar&baz=qux".</jc> * client * .get(<jsf>URL</jsf>) - * .customQuery(<js>"key1=val1&key2=val2"</js>) + * .queryCustom(<js>"foo=bar&baz=qux"</js>) * .run(); * </p> * @@ -1717,25 +1351,31 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur return this; } - @SuppressWarnings("unchecked") - RestRequest query(EnumSet<AddFlag> flags, String name, Object value, HttpPartSchema schema, HttpPartSerializerSession serializer) throws RestCallException { + RestRequest queryArg(EnumSet<AddFlag> flags, String name, Object value, HttpPartSchema schema, HttpPartSerializerSession serializer) throws RestCallException { serializer = (serializer == null ? partSerializer : serializer); flags = AddFlag.orDefault(flags); boolean isMulti = isEmpty(name) || "*".equals(name) || value instanceof NameValuePairs; - if (! isMulti) { - innerQuery(flags, AList.of(toQuery(flags, name, value, serializer, schema))); - } else if (value instanceof NameValuePairs) { - innerQuery(flags, AList.of((NameValuePairs)value)); + + if (! isMulti) + return innerQuery(flags, AList.of(serializedNameValuePair(name, value, QUERY, serializer, schema, flags))); + + List<NameValuePair> l = AList.of(); + + if (value instanceof NameValuePairs) { + l.addAll((NameValuePairs)value); } else if (value instanceof Map) { - innerQuery(flags, toQuery(flags, (Map<String,Object>)value, serializer, schema)); + for (Map.Entry<Object,Object> e : toMap(value).entrySet()) + l.add(serializedNameValuePair(e.getKey(), e.getValue(), QUERY, serializer, schema, flags)); } else if (isBean(value)) { - query(flags, name, toBeanMap(value), schema, serializer); + for (Map.Entry<String,Object> e : toBeanMap(value).entrySet()) + l.add(serializedNameValuePair(e.getKey(), e.getValue(), QUERY, serializer, schema, flags)); } else if (value instanceof Reader || value instanceof InputStream || value instanceof CharSequence) { - queryCustom(value); + return queryCustom(value); } else { throw new RestCallException("Invalid name ''{0}'' passed to query() for data type ''{1}''", name, className(value)); } - return this; + + return innerQuery(flags, l); } private RestRequest innerQuery(EnumSet<AddFlag> flags, List<NameValuePair> params) { @@ -1772,6 +1412,18 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur /** * Adds a form-data parameter to the request body. * + * <h5 class='section'>Example:</h5> + * <p class='bcode w800'> + * <jc>// Adds form data parameter "foo=bar|baz".</jc> + * client + * .formPost(<jsf>URL</jsf>) + * .formData( + * EnumSet.<jsm>of</jsm>(<jsf>APPEND</jsf>,<jsf>SKIP_IF_EMPTY</jsf>), + * <js>"foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), + * HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf> + * .run(); + * </p> + * * @param flags Instructions on how to add this parameter. * <ul> * <li>{@link AddFlag#APPEND APPEND} (default) - Append to end. @@ -1780,34 +1432,10 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * <li>{@link AddFlag#SKIP_IF_EMPTY} - Don't add if value is an empty string. * </ul> * @param name The parameter name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of parameters. - * </ul> * @param value The parameter value. * <ul> - * <li>For single value parameters: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value parameters: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li>{@link Reader} / {@link InputStream} / {@link CharSequence} / {@link HttpEntity} - * <ul> - * <li>Sets the entire query string to the contents of the input. - * </ul> - * </ul> + * <li>Value can be any POJO. + * <li>Value converted to a string using the configured part serializer. * </ul> * @param schema The schema object that defines the format of the output. * <ul> @@ -1818,59 +1446,7 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * @throws RestCallException Invalid input. */ public RestRequest formData(EnumSet<AddFlag> flags, String name, Object value, HttpPartSchema schema) throws RestCallException { - return formData(flags, name, value, schema, partSerializer); - } - - /** - * Adds a form-data parameter to the request body. - * - * @param flags Instructions on how to add this parameter. - * <ul> - * <li>{@link AddFlag#APPEND APPEND} (default) - Append to end. - * <li>{@link AddFlag#PREPEND PREPEND} - Prepend to beginning. - * <li>{@link AddFlag#REPLACE REPLACE} - Delete any existing with same name and append to end. - * <li>{@link AddFlag#SKIP_IF_EMPTY} - Don't add if value is an empty string. - * </ul> - * @param name The parameter name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of parameters. - * </ul> - * @param value The parameter value supplier. - * <ul> - * <li>For single value parameters: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value parameters: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li>{@link Reader} / {@link InputStream} / {@link CharSequence} / {@link HttpEntity} - * <ul> - * <li>Sets the entire query string to the contents of the input. - * </ul> - * </ul> - * </ul> - * @param schema The schema object that defines the format of the output. - * <ul> - * <li>If <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. - * <li>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}). - * </ul> - * @return This object (for method chaining). - * @throws RestCallException Invalid input. - */ - public RestRequest formData(EnumSet<AddFlag> flags, String name, Supplier<?> value, HttpPartSchema schema) throws RestCallException { - return formData(flags, name, value, schema, partSerializer); + return formDatas(flags, serializedNameValuePair(name, value, FORMDATA, partSerializer, schema, flags)); } /** @@ -1878,6 +1454,7 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Adds form data parameter "foo=bar|baz".</jc> * client * .formPost(<jsf>URL</jsf>) * .formData(<js>"foo"</js>, <js>"bar"</js>) @@ -1885,40 +1462,16 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * </p> * * @param name The parameter name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of parameters. - * </ul> * @param value The parameter value. * <ul> - * <li>For single value parameters: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value parameters: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li>{@link Reader} / {@link InputStream} / {@link CharSequence} - * <ul> - * <li>Sets the entire query string to the contents of the input. - * </ul> - * </ul> + * <li>Value can be any POJO. + * <li>Value converted to a string using the configured part serializer. * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ public RestRequest formData(String name, Object value) throws RestCallException { - return formData(DEFAULT_FLAGS, name, value, null, partSerializer); + return formDatas(serializedNameValuePair(name, value, FORMDATA, partSerializer, null, null)); } /** @@ -1926,6 +1479,7 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Adds form data parameter "foo=bar".</jc> * client * .formPost(<jsf>URL</jsf>) * .formData(BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>, <js>"bar"</js>)) @@ -1943,169 +1497,52 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur /** * Adds a form-data parameter to the request body. * - * <h5 class='section'>Example:</h5> - * <p class='bcode w800'> - * client - * .formPost(<jsf>URL</jsf>) - * .formData(<js>"foo"</js>, ()-><js>"bar"</js>) - * .run(); - * </p> - * - * @param name The parameter name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of parameters. - * </ul> - * @param value The parameter value supplier. - * <ul> - * <li>For single value parameters: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value parameters: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li>{@link Reader} / {@link InputStream} / {@link CharSequence} - * <ul> - * <li>Sets the entire query string to the contents of the input. - * </ul> - * </ul> - * </ul> - * @return This object (for method chaining). - * @throws RestCallException Invalid input. - */ - public RestRequest formData(String name, Supplier<?> value) throws RestCallException { - return formData(DEFAULT_FLAGS, name, value, null, partSerializer); - } - - /** - * Adds a form-data parameter to the request body. - * * <p> * The optional schema allows for specifying how part should be serialized (as a pipe-delimited list for example). * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> - * <jc>// Creates form-data parameter "foo=bar|baz"</jc> + * <jc>// Adds form data parameter "foo=bar|baz".</jc> * client * .formPost(<jsf>URL</jsf>) - * .formData(<js>"foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf>) + * .formData( + * <js>"foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), + * HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf> + * ) * .run(); * </p> * * @param name The parameter name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of parameters. - * </ul> * @param value The parameter value. * <ul> - * <li>For single value parameters: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value parameters: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li>{@link Reader} / {@link InputStream} / {@link CharSequence} - * <ul> - * <li>Sets the entire query string to the contents of the input. - * </ul> - * </ul> + * <li>Value can be any POJO. + * <li>Value converted to a string using the configured part serializer. * </ul> * @param schema The HTTP part schema. Can be <jk>null</jk>. * @return This object (for method chaining). * @throws RestCallException Invalid input. */ public RestRequest formData(String name, Object value, HttpPartSchema schema) throws RestCallException { - return formData(DEFAULT_FLAGS, name, value, schema, partSerializer); + return formDatas(serializedNameValuePair(name, value, FORMDATA, partSerializer, schema, null)); } /** * Adds a form-data parameter to the request body. * - * <p> - * The optional schema allows for specifying how part should be serialized (as a pipe-delimited list for example). - * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> - * <jc>// Creates form-data parameter "foo=bar|baz"</jc> + * <jc>// Adds form data parameter "foo=bar".</jc> * client * .formPost(<jsf>URL</jsf>) - * .formData(<js>"foo"</js>, ()->AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf>) + * .formData( + * EnumSet.<jsm>of</jsm>(<jsf>APPEND</jsf>,<jsf>SKIP_IF_EMPTY</jsf>), + * <js>"foo"</js>, <js>"bar"</js> + * ) * .run(); * </p> * - * @param name The parameter name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of parameters. - * </ul> - * @param value The parameter value supplier. - * <ul> - * <li>For single value parameters: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value parameters: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li>{@link Reader} / {@link InputStream} / {@link CharSequence} - * <ul> - * <li>Sets the entire query string to the contents of the input. - * </ul> - * </ul> - * </ul> - * @param schema The HTTP part schema. Can be <jk>null</jk>. - * @return This object (for method chaining). - * @throws RestCallException Invalid input. - */ - public RestRequest formData(String name, Supplier<?> value, HttpPartSchema schema) throws RestCallException { - return formData(DEFAULT_FLAGS, name, value, schema, partSerializer); - } - - /** - * Adds a form-data parameter to the request body. - * - * <h5 class='section'>Example:</h5> - * <p class='bcode w800'> - * client - * .formPost(<jsf>URL</jsf>) - * .formData(EnumSet.<jsm>of</jsm>(<jsf>REPLACE</jsf>,<jsf>SKIP_IF_EMPTY</jsf>), <js>"foo"</js>, <js>"bar"</js>) - * .run(); - * </p> - * - * @param flags Instructions on how to add this parameter. + * @param flags + * Instructions on how to add this parameter. * <ul> * <li>{@link AddFlag#APPEND APPEND} (default) - Append to end. * <li>{@link AddFlag#PREPEND PREPEND} - Prepend to beginning. @@ -2113,95 +1550,16 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * <li>{@link AddFlag#SKIP_IF_EMPTY} - Don't add if value is an empty string. * </ul> * @param name The parameter name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of parameters. - * </ul> * @param value The parameter value. * <ul> - * <li>For single value parameters: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value parameters: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li>{@link Reader} / {@link InputStream} / {@link CharSequence} - * <ul> - * <li>Sets the entire query string to the contents of the input. - * </ul> - * </ul> + * <li>Value can be any POJO. + * <li>Value converted to a string using the configured part serializer. * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ public RestRequest formData(EnumSet<AddFlag> flags, String name, Object value) throws RestCallException { - return formData(flags, name, value, null, partSerializer); - } - - /** - * Adds a form-data parameter to the request body. - * - * <h5 class='section'>Example:</h5> - * <p class='bcode w800'> - * client - * .formPost(<jsf>URL</jsf>) - * .formData(EnumSet.<jsm>of</jsm>(<jsf>REPLACE</jsf>,<jsf>SKIP_IF_EMPTY</jsf>), <js>"foo"</js>, ()-><js>"bar"</js>) - * .run(); - * </p> - * - * @param flags Instructions on how to add this parameter. - * <ul> - * <li>{@link AddFlag#APPEND APPEND} (default) - Append to end. - * <li>{@link AddFlag#PREPEND PREPEND} - Prepend to beginning. - * <li>{@link AddFlag#REPLACE REPLACE} - Delete any existing with same name and append to end. - * <li>{@link AddFlag#SKIP_IF_EMPTY} - Don't add if value is an empty string. - * </ul> - * @param name The parameter name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of parameters. - * </ul> - * @param value The parameter value supplier. - * <ul> - * <li>For single value parameters: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value parameters: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li>{@link Reader} / {@link InputStream} / {@link CharSequence} - * <ul> - * <li>Sets the entire query string to the contents of the input. - * </ul> - * </ul> - * </ul> - * @return This object (for method chaining). - * @throws RestCallException Invalid input. - */ - public RestRequest formData(EnumSet<AddFlag> flags, String name, Supplier<?> value) throws RestCallException { - return formData(flags, name, value, null, partSerializer); + return formDatas(flags, serializedNameValuePair(name, value, FORMDATA, partSerializer, null, flags)); } /** @@ -2209,43 +1567,42 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Adds form data parameters "foo=bar&baz=qux".</jc> * client * .formPost(<jsf>URL</jsf>) - * .formData(BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>, <js>"bar"</js>)) + * .formDatas( + * BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>), + * AMap.<jsm>of</jsm>(<js>"baz"<j/s>,<js>"qux"</js>) + * ) * .run(); * </p> * * @param params The parameters to set. * <br>Can be any of the following types: * <ul> - * <li>{@link NameValuePair} - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li><jk>null</jk> - Will be a no-op. + * <li>{@link Map} / {@link OMap} / bean - Converted to key/value pairs using part serializer. + * <li>{@link NameValuePair} / {@link NameValuePairs} - Converted to key/value pairs directly. * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ public RestRequest formDatas(Object...params) throws RestCallException { - return formData(DEFAULT_FLAGS, params); + return formDatas(DEFAULT_FLAGS, params); } /** - * Adds a form-data parameter to the request body. + * Adds multiple form-data parameters to the request body. * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Adds form data parameters "foo=bar&baz=qux".</jc> * client * .formPost(<jsf>URL</jsf>) - * .formData(EnumSet.<jsm>of</jsm>(<jsf>REPLACE</jsf>,<jsf>SKIP_IF_EMPTY</jsf>), BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>, <js>"bar"</js>)) + * .formDatas( + * EnumSet.<jsm>of</jsm>(<jsf>APPEND</jsf>,<jsf>SKIP_IF_EMPTY</jsf>), + * BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>), + * AMap.<jsm>of</jsm>(<js>"baz"<j/s>,<js>"qux"</js>) + * ) * .run(); * </p> * @@ -2259,42 +1616,27 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * @param params The parameters to set. * <br>Can be any of the following types: * <ul> - * <li>{@link NameValuePair} - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li><jk>null</jk> - Will be a no-op. + * <li>{@link Map} / {@link OMap} / bean - Converted to key/value pairs using part serializer. + * <li>{@link NameValuePair} / {@link NameValuePairs} - Converted to key/value pairs directly. * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ - @SuppressWarnings("rawtypes") - public RestRequest formData(EnumSet<AddFlag> flags, Object...params) throws RestCallException { + public RestRequest formDatas(EnumSet<AddFlag> flags, Object...params) throws RestCallException { List<NameValuePair> l = new ArrayList<>(); - boolean skipIfEmpty = flags.contains(SKIP_IF_EMPTY); for (Object o : params) { if (o instanceof NameValuePair) { l.add((NameValuePair)o); } else if (o instanceof NameValuePairs) { l.addAll((NameValuePairs)o); } else if (o instanceof Map) { - Map m = (Map)o; - for (Map.Entry e : (Set<Map.Entry>)m.entrySet()) - l.add(new SerializedNameValuePair(stringify(e.getKey()), e.getValue(), FORMDATA, partSerializer, null, skipIfEmpty)); + for (Map.Entry<Object,Object> e : toMap(o).entrySet()) + l.add(serializedNameValuePair(e.getKey(), e.getValue(), FORMDATA, partSerializer, null, flags)); } else if (isBean(o)) { for (Map.Entry<String,Object> e : toBeanMap(o).entrySet()) - l.add(new SerializedNameValuePair(stringify(e.getKey()), e.getValue(), FORMDATA, partSerializer, null, skipIfEmpty)); - } else if (o instanceof Reader || o instanceof InputStream || o instanceof CharSequence || o instanceof HttpEntity) { - formDataCustom(o); + l.add(serializedNameValuePair(e.getKey(), e.getValue(), FORMDATA, partSerializer, null, flags)); } else { - throw new RestCallException("Invalid type passed to formData(): " + o.getClass().getName()); + throw new RestCallException("Invalid type passed to formDatas(): " + o.getClass().getName()); } } return innerFormData(flags, l); @@ -2305,6 +1647,7 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Creates form data "key1=val1&key2=val2".</jc> * client * .formPost(<jsf>URL</jsf>) * .formDataPairs(<js>"key1"</js>,<js>"val1"</js>,<js>"key2"</js>,<js>"val2"</js>) @@ -2315,16 +1658,15 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * <ul> * <li>Values can be any POJO. * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ public RestRequest formDataPairs(Object...pairs) throws RestCallException { if (pairs.length % 2 != 0) - throw new RestCallException("Odd number of parameters passed into formData(Object...)"); + throw new RestCallException("Odd number of parameters passed into formDataPairs()"); for (int i = 0; i < pairs.length; i+=2) - formDatas(new SerializedNameValuePair(stringify(pairs[i]), pairs[i+1], FORMDATA, partSerializer, null, false)); + formDatas(serializedNameValuePair(pairs[i], pairs[i+1], FORMDATA, partSerializer, null, null)); return this; } @@ -2333,9 +1675,22 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Creates form data "foo=bar&baz=qux".</jc> * client * .formPost(<jsf>URL</jsf>) - * .customFormData(<js>"key1=val1&key2=val2"</js>) + * .formDataCustom(<js>"foo=bar&baz=qux"</js>) + * .run(); + * + * <jc>// Creates form data "foo=bar&baz=qux" using StringEntity.</jc> + * client + * .formPost(<jsf>URL</jsf>) + * .formDataCustom(<js>new</js> StringEntity(<js>"foo=bar&baz=qux"</js>,<js>"application/x-www-form-urlencoded"</js>)) + * .run(); + * + * <jc>// Creates form data "foo=bar&baz=qux" using StringEntity and body().</jc> + * client + * .formPost(<jsf>URL</jsf>) + * .body(<js>new</js> StringEntity(<js>"foo=bar&baz=qux"</js>,<js>"application/x-www-form-urlencoded"</js>)) * .run(); * </p> * @@ -2369,29 +1724,31 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur return this; } - @SuppressWarnings("unchecked") - RestRequest formData(EnumSet<AddFlag> flags, String name, Object value, HttpPartSchema schema, HttpPartSerializerSession serializer) throws RestCallException { + RestRequest formDataArg(EnumSet<AddFlag> flags, String name, Object value, HttpPartSchema schema, HttpPartSerializerSession serializer) throws RestCallException { serializer = (serializer == null ? partSerializer : serializer); flags = AddFlag.orDefault(flags); boolean isMulti = isEmpty(name) || "*".equals(name) || value instanceof NameValuePairs; - if (! isMulti) { - innerFormData(flags, toQuery(flags, name, value, serializer, schema)); - } else if (value instanceof NameValuePairs) { - innerFormData(flags, AList.of((NameValuePairs)value)); + + if (! isMulti) + return innerFormData(flags, AList.of(serializedNameValuePair(name, value, FORMDATA, serializer, schema, flags))); + + List<NameValuePair> l = AList.of(); + + if (value instanceof NameValuePairs) { + l.addAll((NameValuePairs)value); } else if (value instanceof Map) { - innerFormData(flags, toQuery(flags, (Map<String,Object>)value, serializer, schema)); + for (Map.Entry<Object,Object> e : toMap(value).entrySet()) + l.add(serializedNameValuePair(e.getKey(), e.getValue(), FORMDATA, serializer, schema, flags)); } else if (isBean(value)) { - formData(flags, name, toBeanMap(value), schema, serializer); - } else if (value instanceof Reader || value instanceof InputStream || value instanceof CharSequence || value instanceof HttpEntity) { - formDataCustom(value); + for (Map.Entry<String,Object> e : toBeanMap(value).entrySet()) + l.add(serializedNameValuePair(e.getKey(), e.getValue(), FORMDATA, serializer, schema, flags)); + } else if (value instanceof Reader || value instanceof InputStream || value instanceof CharSequence) { + return formDataCustom(value); } else { throw new RestCallException("Invalid name ''{0}'' passed to formData() for data type ''{1}''", name, className(value)); } - return this; - } - private RestRequest innerFormData(EnumSet<AddFlag> flags, NameValuePair param) { - return innerFormData(flags, AList.of(param)); + return innerFormData(flags, l); } private RestRequest innerFormData(EnumSet<AddFlag> flags, List<NameValuePair> params) { @@ -2533,7 +1890,20 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur //----------------------------------------------------------------------------------------------------------------- /** - * Sets a header on the request. + * Adds a header on the request. + * + * <h5 class='section'>Example:</h5> + * <p class='bcode w800'> + * <jc>// Adds header "Foo: bar|baz".</jc> + * client + * .get(<jsf>URL</jsf>) + * .header( + * EnumSet.<jsm>of</jsm>(<jsf>APPEND</jsf>,<jsf>SKIP_IF_EMPTY</jsf>), + * <js>"Foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>)), + * HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf> + * ) + * .run(); + * </p> * * @param flags Instructions on how to add this parameter. * <ul> @@ -2543,32 +1913,12 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * <li>{@link AddFlag#SKIP_IF_EMPTY} - Don't add if value is an empty string. * </ul> * @param name The header name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of headers. - * </ul> * @param value The header value. * <ul> - * <li>For single value headers: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value headers: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * </ul> + * <li>Value can be any POJO. + * <li>Value converted to a string using the configured part serializer. * </ul> - * @param schema The schema object that defines the format of the output. + * @param schema The schema object that defines the format of the output. * <ul> * <li>If <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. * <li>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}). @@ -2577,55 +1927,7 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * @throws RestCallException Invalid input. */ public RestRequest header(EnumSet<AddFlag> flags, String name, Object value, HttpPartSchema schema) throws RestCallException { - return header(flags, name, value, schema, partSerializer); - } - - /** - * Sets a header on the request. - * - * @param flags Instructions on how to add this parameter. - * <ul> - * <li>{@link AddFlag#APPEND APPEND} (default) - Append to end. - * <li>{@link AddFlag#PREPEND PREPEND} - Prepend to beginning. - * <li>{@link AddFlag#REPLACE REPLACE} - Delete any existing with same name and append to end. - * <li>{@link AddFlag#SKIP_IF_EMPTY} - Don't add if value is an empty string. - * </ul> - * @param name The header name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of headers. - * </ul> - * @param value The header value supplier. - * <ul> - * <li>For single value headers: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value headers: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * </ul> - * </ul> - * @param schema The schema object that defines the format of the output. - * <ul> - * <li>If <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. - * <li>Only used if serializer is schema-aware (e.g. {@link OpenApiSerializer}). - * </ul> - * @return This object (for method chaining). - * @throws RestCallException Invalid input. - */ - public RestRequest header(EnumSet<AddFlag> flags, String name, Supplier<?> value, HttpPartSchema schema) throws RestCallException { - return header(flags, name, value, schema, partSerializer); + return headers(flags, serializedHeader(name, value, partSerializer, schema, flags)); } /** @@ -2633,6 +1935,7 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Adds header "Foo: bar".</jc> * client * .get(<jsf>URL</jsf>) * .header(<js>"Foo"</js>, <js>"bar"</js>) @@ -2640,80 +1943,16 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * </p> * * @param name The header name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of headers. - * </ul> * @param value The header value. * <ul> - * <li>For single value headers: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value headers: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * </ul> + * <li>Value can be any POJO. + * <li>Value converted to a string using the configured part serializer. * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ public RestRequest header(String name, Object value) throws RestCallException { - return header(DEFAULT_FLAGS, name, value, null, partSerializer); - } - - /** - * Appends a header on the request. - * - * <h5 class='section'>Example:</h5> - * <p class='bcode w800'> - * client - * .get(<jsf>URL</jsf>) - * .header(<js>"Foo"</js>, ()-><js>"bar"</js>) - * .run(); - * </p> - * - * @param name The header name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of headers. - * </ul> - * @param value The header value. - * <ul> - * <li>For single value headers: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value headers: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * </ul> - * </ul> - * @return This object (for method chaining). - * @throws RestCallException Invalid input. - */ - public RestRequest header(String name, Supplier<?> value) throws RestCallException { - return header(DEFAULT_FLAGS, name, value, null, partSerializer); + return headers(serializedHeader(name, value, partSerializer, null, null)); } /** @@ -2724,104 +1963,42 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> - * <jc>// Creates header "Foo=bar|baz"</jc> + * <jc>// Adds header "Foo: bar|baz".</jc> * client * .get(<jsf>URL</jsf>) - * .header(<js>"Foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf>) + * .header( + * <js>"Foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), + * HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf> + * ) * .run(); * </p> * * @param name The header name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of headers. - * </ul> * @param value The header value. * <ul> - * <li>For single value headers: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value headers: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * </ul> + * <li>Value can be any POJO. + * <li>Value converted to a string using the configured part serializer. * </ul> * @param schema The HTTP part schema. Can be <jk>null</jk>. * @return This object (for method chaining). * @throws RestCallException Invalid input. */ public RestRequest header(String name, Object value, HttpPartSchema schema) throws RestCallException { - return header(DEFAULT_FLAGS, name, value, schema, partSerializer); - } - - /** - * Appends a header on the request. - * - * <p> - * The optional schema allows for specifying how part should be serialized (as a pipe-delimited list for example). - * - * <h5 class='section'>Example:</h5> - * <p class='bcode w800'> - * <jc>// Creates header "Foo=bar|baz"</jc> - * client - * .get(<jsf>URL</jsf>) - * .header(<js>"Foo"</js>, ()->AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), HttpPartSchema.<jsf>T_ARRAY_PIPES</jsf>) - * .run(); - * </p> - * - * @param name The header name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of headers. - * </ul> - * @param value The header value. - * <ul> - * <li>For single value headers: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value headers: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * </ul> - * </ul> - * @param schema The HTTP part schema. Can be <jk>null</jk>. - * @return This object (for method chaining). - * @throws RestCallException Invalid input. - */ - public RestRequest header(String name, Supplier<?> value, HttpPartSchema schema) throws RestCallException { - return header(DEFAULT_FLAGS, name, value, schema, partSerializer); + return headers(serializedHeader(name, value, partSerializer, schema, null)); } /** - * Sets a header on the request. + * Adds a header to the request. * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Adds header "Foo: bar".</jc> * client * .get(<jsf>URL</jsf>) - * .header(EnumSet.<jsm>of</jsm>(<jsf>REPLACE</jsf>,<jsf>SKIP_IF_EMPTY</jsf>),<js>"Foo"</js>, <js>"bar"</js>) + * .header( + * EnumSet.<jsm>of</jsm>(<jsf>APPEND</jsf>,<jsf>SKIP_IF_EMPTY</jsf>), + * <js>"Foo"</js>, <js>"bar"</js> + * ) * .run(); * </p> * @@ -2833,87 +2010,16 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * <li>{@link AddFlag#SKIP_IF_EMPTY} - Don't add if value is an empty string. * </ul> * @param name The header name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of headers. - * </ul> * @param value The header value. * <ul> - * <li>For single value headers: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value headers: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * </ul> + * <li>Value can be any POJO. + * <li>Value converted to a string using the configured part serializer. * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ public RestRequest header(EnumSet<AddFlag> flags, String name, Object value) throws RestCallException { - return header(flags, name, value, null, partSerializer); - } - - /** - * Sets a header on the request. - * - * <h5 class='section'>Example:</h5> - * <p class='bcode w800'> - * client - * .get(<jsf>URL</jsf>) - * .header(EnumSet.<jsm>of</jsm>(<jsf>REPLACE</jsf>,<jsf>SKIP_IF_EMPTY</jsf>),<js>"Foo"</js>, ()-><js>"bar"</js>) - * .run(); - * </p> - * - * @param flags Instructions on how to add this parameter. - * <ul> - * <li>{@link AddFlag#APPEND APPEND} (default) - Append to end. - * <li>{@link AddFlag#PREPEND PREPEND} - Prepend to beginning. - * <li>{@link AddFlag#REPLACE REPLACE} - Delete any existing with same name and append to end. - * <li>{@link AddFlag#SKIP_IF_EMPTY} - Don't add if value is an empty string. - * </ul> - * @param name The header name. - * <ul> - * <li>If the name is <js>"*"</js>, the value is assumed to be a collection of headers. - * </ul> - * @param value The header value supplier. - * <ul> - * <li>For single value headers: - * <ul> - * <li>Can be any POJO. - * <li>Converted to a string using the specified part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>For multi-value headers: - * <ul> - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * </ul> - * </ul> - * @return This object (for method chaining). - * @throws RestCallException Invalid input. - */ - public RestRequest header(EnumSet<AddFlag> flags, String name, Supplier<?> value) throws RestCallException { - return header(flags, name, value, null, partSerializer); + return headers(flags, serializedHeader(name, value, partSerializer, null, flags)); } /** @@ -2921,6 +2027,7 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Adds header "Foo: bar".</jc> * client * .get(<jsf>URL</jsf>) * .header(BasicHeader.<jsm>of</jsm>(<js>"Foo"</js>, <js>"bar"</js>)) @@ -2932,17 +2039,18 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * @throws RestCallException Invalid input. */ public RestRequest header(Header header) throws RestCallException { - return header(DEFAULT_FLAGS, header); + return headers(header); } /** * Appends a header on the request. * * <h5 class='section'>Example:</h5> + * <jc>// Adds header "Foo: bar".</jc> * <p class='bcode w800'> * client * .get(<jsf>URL</jsf>) - * .header(BasicNameValuePair.<jsm>of</jsm>(BasicHeader.<jsm>of</jsm>(<js>"Foo"</js>, <js>"bar"</js>))) + * .header(BasicNameValuePair.<jsm>of</jsm>(<js>"Foo"</js>, <js>"bar"</js>)) * .run(); * </p> * @@ -2951,44 +2059,7 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * @throws RestCallException Invalid input. */ public RestRequest header(NameValuePair header) throws RestCallException { - return header(DEFAULT_FLAGS, header); - } - - /** - * Sets a header on the request. - * - * <h5 class='section'>Example:</h5> - * <p class='bcode w800'> - * client - * .get(<jsf>URL</jsf>) - * .header(EnumSet.<jsm>of</jsm>(<jsf>REPLACE</jsf>,<jsf>SKIP_IF_EMPTY</jsf>),BasicHeader.<jsm>of</jsm>(<js>"Foo"</js>, <js>"bar"</js>)) - * .run(); - * </p> - * - * @param flags Instructions on how to add this parameter. - * <ul> - * <li>{@link AddFlag#APPEND APPEND} (default) - Append to end. - * <li>{@link AddFlag#PREPEND PREPEND} - Prepend to beginning. - * <li>{@link AddFlag#REPLACE REPLACE} - Delete any existing with same name and append to end. - * <li>{@link AddFlag#SKIP_IF_EMPTY} - Don't add if value is an empty string. - * </ul> - * @param header The header to set. - * <br>Can be any of the following types: - * <ul> - * <li>{@link Header} (including any subclasses such as {@link Accept}) - * <li>{@link NameValuePair} - * <li><jk>null</jk> - Will be a no-op. - * </ul> - * @return This object (for method chaining). - * @throws RestCallException Invalid input. - */ - public RestRequest header(EnumSet<AddFlag> flags, Object header) throws RestCallException { - if (header == null) - return this; - Header h = toHeader(header); - if (h == null) - throw new RestCallException("Invalid type passed to header(): " + header.getClass().getName()); - return innerHeader(flags, h); + return headers(header); } /** @@ -2996,28 +2067,21 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Adds headers "Foo: bar" and "Baz: qux".</jc> * client * .get(<jsf>URL</jsf>) - * .headers(BasicHeader.<jsm>of</jsm>(<js>"Foo"</js>, <js>"bar"</js>)) + * .headers( + * BasicHeader.<jsm>of</jsm>(<js>"Foo"</js>, <js>"bar"</js>), + * AMap.<jsm>of</jsm>(<js>"Baz"</js>, <js>"qux"</js>) + * ) * .run(); * </p> * - * @param headers The header to set. + * @param headers The headers to set. * <br>Can be any of the following types: * <ul> - * <li>{@link Header} (including any subclasses such as {@link Accept}) - * <li>{@link NameValuePair} - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li><jk>null</jk> - Will be a no-op. + * <li>{@link Map} / {@link OMap} / bean - Converted to key/value pairs using part serializer. + * <li>{@link Header} / {@link NameValuePair} / {@link NameValuePairs} - Converted to key/value pairs directly. * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. @@ -3031,9 +2095,14 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Adds headers "Foo: bar" and "Baz: qux".</jc> * client * .get(<jsf>URL</jsf>) - * .headers(EnumSet.<jsm>of</jsm>(<jsf>REPLACE</jsf>,<jsf>SKIP_IF_EMPTY</jsf>),BasicHeader.<jsm>of</jsm>(<js>"Foo"</js>, <js>"bar"</js>)) + * .headers( + * EnumSet.<jsm>of</jsm>(<jsf>APPEND</jsf>,<jsf>SKIP_IF_EMPTY</jsf>), + * BasicHeader.<jsm>of</jsm>(<js>"Foo"</js>, <js>"bar"</js>), + * AMap.<jsm>of</jsm>(<js>"Baz"</js>, <js>"qux"</js>) + * ) * .run(); * </p> * @@ -3044,27 +2113,15 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * <li>{@link AddFlag#REPLACE REPLACE} - Delete any existing with same name and append to end. * <li>{@link AddFlag#SKIP_IF_EMPTY} - Don't add if value is an empty string. * </ul> - * @param headers The header to set. + * @param headers The headers to set. * <br>Can be any of the following types: * <ul> - * <li>{@link Header} (including any subclasses such as {@link Accept}) - * <li>{@link NameValuePair} - * <li>{@link Map} / {@link OMap} / bean - * <ul> - * <li>Values can be any POJO. - * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. - * </ul> - * <li>{@link NameValuePairs} - * <ul> - * <li>Values converted directly to strings. - * </ul> - * <li><jk>null</jk> - Will be a no-op. + * <li>{@link Map} / {@link OMap} / bean - Converted to key/value pairs using part serializer. + * <li>{@link Header} / {@link NameValuePair} / {@link NameValuePairs} - Converted to key/value pairs directly. * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ - @SuppressWarnings("rawtypes") public RestRequest headers(EnumSet<AddFlag> flags, Object...headers) throws RestCallException { List<Header> l = new ArrayList<>(); for (Object o : headers) { @@ -3074,14 +2131,13 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur for (NameValuePair p : (NameValuePairs)o) l.add(toHeader(p)); } else if (o instanceof Map) { - Map m = (Map)o; - for (Map.Entry e : (Set<Map.Entry>)m.entrySet()) - l.add(new SerializedHeader(stringify(e.getKey()), e.getValue(), partSerializer, null, flags.contains(SKIP_IF_EMPTY))); + for (Map.Entry<Object,Object> e : toMap(o).entrySet()) + l.add(serializedHeader(e.getKey(), e.getValue(), partSerializer, null, flags)); } else if (isBean(o)) { for (Map.Entry<String,Object> e : toBeanMap(o).entrySet()) - l.add(new SerializedHeader(stringify(e.getKey()), e.getValue(), partSerializer, null, flags.contains(SKIP_IF_EMPTY))); + l.add(serializedHeader(e.getKey(), e.getValue(), partSerializer, null, flags)); } else { - throw new RestCallException("Invalid type passed to header(): " + headers.getClass().getName()); + throw new RestCallException("Invalid type passed to headers(): " + className(o)); } } return innerHeaders(flags, l); @@ -3092,17 +2148,17 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * * <h5 class='section'>Example:</h5> * <p class='bcode w800'> + * <jc>// Adds headers "Foo: bar" and "Baz: qux".</jc> * client * .get(<jsf>URL</jsf>) - * .headers(<js>"Header1"</js>,<js>"val1"</js>,<js>"Header2"</js>,<js>"val2"</js>) + * .headers(<js>"Foo"</js>,<js>"bar"</js>,<js>"Baz"</js>,<js>"qux"</js>) * .run(); * </p> * - * @param pairs The header key/value pairs. + * @param pairs The form-data key/value pairs. * <ul> * <li>Values can be any POJO. * <li>Values converted to a string using the configured part serializer. - * <li>Values are converted to strings at runtime to allow them to be modified externally. * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. @@ -3110,33 +2166,39 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur public RestRequest headerPairs(Object...pairs) throws RestCallException { List<Header> l = new ArrayList<>(); if (pairs.length % 2 != 0) - throw new RestCallException("Odd number of parameters passed into headerPairs(Object...)"); + throw new RestCallException("Odd number of parameters passed into headerPairs()"); for (int i = 0; i < pairs.length; i+=2) - l.add(new SerializedHeader(stringify(pairs[i]), pairs[i+1], partSerializer, null, false)); + l.add(serializedHeader(pairs[i], pairs[i+1], partSerializer, null, null)); return innerHeaders(DEFAULT_FLAGS, l); } - @SuppressWarnings("unchecked") - RestRequest header(EnumSet<AddFlag> flags, String name, Object value, HttpPartSchema schema, HttpPartSerializerSession serializer) throws RestCallException { + RestRequest headerArg(EnumSet<AddFlag> flags, String name, Object value, HttpPartSchema schema, HttpPartSerializerSession serializer) throws RestCallException { serializer = (serializer == null ? partSerializer : serializer); flags = AddFlag.orDefault(flags); boolean isMulti = isEmpty(name) || "*".equals(name) || value instanceof NameValuePairs; - if (! isMulti) { - innerHeader(flags, toHeader(flags, name, value, serializer, schema)); + + + if (! isMulti) + return innerHeaders(flags, AList.of(serializedHeader(name, value, serializer, schema, flags))); + + List<Header> l = AList.of(); + + if (value instanceof Headerable) { + l.add(((Headerable)value).asHeader()); } else if (value instanceof NameValuePairs) { - innerHeaders(flags, toHeaders((NameValuePairs)value)); + for (NameValuePair p : (NameValuePairs)value) + l.add(toHeader(p)); } else if (value instanceof Map) { - innerHeaders(flags, toHeaders(flags, (Map<String,Object>)value, serializer, schema)); + for (Map.Entry<Object,Object> e : toMap(value).entrySet()) + l.add(serializedHeader(e.getKey(), e.getValue(), serializer, schema, flags)); } else if (isBean(value)) { - return header(flags, name, toBeanMap(value), schema, serializer); + for (Map.Entry<String,Object> e : toBeanMap(value).entrySet()) + l.add(serializedHeader(e.getKey(), e.getValue(), serializer, schema, flags)); } else { - throw new RestCallException("Invalid name ''{0}'' passed to header(name,value,skipIfEmpty) for data type ''{1}''", name, className(value)); + throw new RestCallException("Invalid name ''{0}'' passed to header() for data type ''{1}''", name, className(value)); } - return this; - } - private RestRequest innerHeader(EnumSet<AddFlag> flags, Header header) { - return innerHeaders(flags, AList.of(header)); + return innerHeaders(flags, l); } private RestRequest innerHeaders(EnumSet<AddFlag> flags, Collection<Header> headers) { @@ -4248,8 +3310,31 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur return super.getProperties(); } - private static String className(Object o) { - return ClassInfo.of(o).getFullName(); + @SuppressWarnings("unchecked") + private static Map<Object,Object> toMap(Object o) { + return (Map<Object,Object>)o; + } + + private static SerializedNameValuePair serializedNameValuePair(Object key, Object value, HttpPartType type, HttpPartSerializerSession serializer, HttpPartSchema schema, EnumSet<AddFlag> flags) { + return new SerializedNameValuePair(stringify(key), value, type, serializer, schema, flags == null ? false : flags.contains(SKIP_IF_EMPTY)); + } + + private static SerializedHeader serializedHeader(Object key, Object value, HttpPartSerializerSession serializer, HttpPartSchema schema, EnumSet<AddFlag> flags) { + return new SerializedHeader(stringify(key), value, serializer, schema, flags == null ? false : flags.contains(SKIP_IF_EMPTY)); + } + + private static Header toHeader(Object o) { + if (o instanceof Header) + return (Header)o; + if (o instanceof Headerable) + return ((Headerable)o).asHeader(); + if (o instanceof NameValuePair) + return BasicHeader.of((NameValuePair)o); + throw new BasicRuntimeException("Object cannot be converted to a header: {0}", o == null ? null : o.getClass().getName()); + } + + private static String className(Object value) { + return value == null ? null : value.getClass().getName(); } //-----------------------------------------------------------------------------------------------------------------