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 859d899 RestClient tests 859d899 is described below commit 859d8994b01d7b5c7158ca7270eae39ff6f0d666 Author: JamesBognar <james.bog...@salesforce.com> AuthorDate: Mon Jun 22 11:59:10 2020 -0400 RestClient tests --- .../org/apache/juneau/http/BasicNameValuePair.java | 38 +++- .../org/apache/juneau/http/NameValuePairable.java | 28 +++ .../org/apache/juneau/http/SerializedHeader.java | 113 +--------- .../juneau/http/SerializedHeaderBuilder.java | 128 +++++++++++ .../juneau/http/SerializedNameValuePair.java | 116 +--------- .../http/SerializedNameValuePairBuilder.java | 138 ++++++++++++ .../org/apache/juneau/http/header/BasicHeader.java | 40 ++++ .../apache/juneau/rest/client2/RestClientTest.java | 2 +- .../org/apache/juneau/rest/client2/RestClient.java | 54 ++--- .../juneau/rest/client2/RestClientBuilder.java | 157 +++++++------ .../apache/juneau/rest/client2/RestRequest.java | 243 +++++++++++++++------ 11 files changed, 655 insertions(+), 402 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 952705e..be5601b 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 @@ -14,14 +14,17 @@ package org.apache.juneau.http; import static org.apache.juneau.internal.StringUtils.*; +import java.util.*; import java.util.function.*; import org.apache.http.*; +import org.apache.juneau.*; import org.apache.juneau.http.header.*; +import org.apache.juneau.reflect.*; /** * 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. @@ -56,6 +59,39 @@ public class BasicNameValuePair implements NameValuePair, Headerable { } /** + * Utility method for converting an arbitrary object to a {@link NameValuePair}. + * + * @param o + * The object to cast or convert to a {@link NameValuePair}. + * @return Either the same object cast as a {@link NameValuePair} or converted to a {@link NameValuePair}. + */ + @SuppressWarnings("rawtypes") + public static NameValuePair cast(Object o) { + if (o instanceof NameValuePair) + return (NameValuePair)o; + if (o instanceof NameValuePairable) + return ((NameValuePairable)o).asNameValuePair(); + if (o instanceof Headerable) + return ((Headerable)o).asHeader(); + if (o instanceof Map.Entry) { + Map.Entry e = (Map.Entry)o; + return BasicNameValuePair.of(stringify(e.getKey()), e.getValue()); + } + throw new BasicRuntimeException("Object of type {0} could not be converted to a NameValuePair.", o == null ? null : o.getClass().getName()); + } + + /** + * Returns <jk>true</jk> if the {@link #cast(Object)} method can be used on the specified object. + * + * @param o The object to check. + * @return <jk>true</jk> if the {@link #cast(Object)} method can be used on the specified object. + */ + public static boolean canCast(Object o) { + ClassInfo ci = ClassInfo.of(o); + return ci != null && ci.isChildOfAny(Headerable.class, NameValuePair.class, NameValuePairable.class, Map.Entry.class); + } + + /** * Constructor. * * @param name The parameter name. diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/NameValuePairable.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/NameValuePairable.java new file mode 100644 index 0000000..6c39b11 --- /dev/null +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/NameValuePairable.java @@ -0,0 +1,28 @@ +// *************************************************************************************************************************** +// * 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 NameValuePair} object. + */ +public interface NameValuePairable { + + /** + * Convert the object to a {@link NameValuePair}. + * + * @return The object converted to a {@link NameValuePair}. + */ + NameValuePair asNameValuePair(); +} 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 032b184..ac68273 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 @@ -36,7 +36,7 @@ import org.apache.juneau.urlencoding.*; * request.setEntity(<jk>new</jk> UrlEncodedFormEntity(params)); * </p> */ -public class SerializedHeader extends BasicStringHeader { +public class SerializedHeader extends BasicStringHeader implements NameValuePairable { private static final long serialVersionUID = 1L; private Object value; @@ -49,8 +49,8 @@ public class SerializedHeader extends BasicStringHeader { * * @return A new builder for this object. */ - public static Builder create() { - return new Builder(); + public static SerializedHeaderBuilder create() { + return new SerializedHeaderBuilder(); } /** @@ -76,113 +76,13 @@ public class SerializedHeader extends BasicStringHeader { this.skipIfEmpty = skipIfEmpty; } - SerializedHeader(Builder b) { + SerializedHeader(SerializedHeaderBuilder b) { super(b.name, null); this.value = b.value; this.serializer = b.serializer; this.schema = b.schema == null ? HttpPartSchema.DEFAULT : b.schema; } - /** - * Builder for {@link SerializedHeader} objects. - */ - public static class Builder { - String name; - Object value; - HttpPartSerializerSession serializer; - HttpPartSchema schema; - - /** - * Sets the parameter name. - * - * @param value The new value for this property. - * @return This object (for method chaining). - */ - public Builder name(String value) { - this.name = value; - return this; - } - - /** - * Sets the POJO to serialize to the parameter value. - * - * @param value The new value for this property. - * @return This object (for method chaining). - */ - public Builder value(Object value) { - this.value = value; - return this; - } - - /** - * Sets the POJO supplier to serialize to the parameter value. - * <p> - * Value is re-evaluated on each call to {@link #getValue()}. - * - * @param value The new value for this property. - * @return This object (for method chaining). - */ - public Builder value(Supplier<?> value) { - this.value = value; - 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(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); - } - - /** - * Sets the serializer to use for serializing the value to a string value. - * - * @param value The new value for this property. - * @param overwrite If <jk>true</jk>, overwrites the existing value if the old value is <jk>null</jk>. - * @return This object (for method chaining). - */ - public Builder serializer(HttpPartSerializerSession value, boolean overwrite) { - if (overwrite || serializer == null) - this.serializer = value; - return this; - } - - /** - * Sets the schema object that defines the format of the output. - * - * @param value The new value for this property. - * @return This object (for method chaining). - */ - public Builder schema(HttpPartSchema value) { - this.schema = value; - return this; - } - - /** - * Creates the new {@link SerializedHeader} - * - * @return The new {@link SerializedHeader} - */ - public SerializedHeader build() { - return new SerializedHeader(this); - } - } - @Override /* NameValuePair */ public String getValue() { try { @@ -202,4 +102,9 @@ public class SerializedHeader extends BasicStringHeader { throw new BasicRuntimeException(e, "Serialization error on request {0} parameter ''{1}''", HttpPartType.HEADER, getName()); } } + + @Override /* NameValuePairable */ + public NameValuePair asNameValuePair() { + return new SerializedNameValuePair(getName(), value, HttpPartType.HEADER, serializer, schema, skipIfEmpty); + } } diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedHeaderBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedHeaderBuilder.java new file mode 100644 index 0000000..473ed9a --- /dev/null +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedHeaderBuilder.java @@ -0,0 +1,128 @@ +// *************************************************************************************************************************** +// * 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 java.util.function.*; + +import org.apache.http.*; +import org.apache.juneau.httppart.*; + +/** + * Builder for {@link SerializedHeader} objects. + */ +public class SerializedHeaderBuilder implements Headerable, NameValuePairable { + String name; + Object value; + HttpPartSerializerSession serializer; + HttpPartSchema schema; + + /** + * Sets the parameter name. + * + * @param value The new value for this property. + * @return This object (for method chaining). + */ + public SerializedHeaderBuilder name(String value) { + this.name = value; + return this; + } + + /** + * Sets the POJO to serialize to the parameter value. + * + * @param value The new value for this property. + * @return This object (for method chaining). + */ + public SerializedHeaderBuilder value(Object value) { + this.value = value; + return this; + } + + /** + * Sets the POJO supplier to serialize to the parameter value. + * <p> + * Value is re-evaluated on each call to {@link Header#getValue()}. + * + * @param value The new value for this property. + * @return This object (for method chaining). + */ + public SerializedHeaderBuilder value(Supplier<?> value) { + this.value = value; + 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 SerializedHeaderBuilder 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 SerializedHeaderBuilder serializer(HttpPartSerializerSession value) { + return serializer(value, true); + } + + /** + * Sets the serializer to use for serializing the value to a string value. + * + * @param value The new value for this property. + * @param overwrite If <jk>true</jk>, overwrites the existing value if the old value is <jk>null</jk>. + * @return This object (for method chaining). + */ + public SerializedHeaderBuilder serializer(HttpPartSerializerSession value, boolean overwrite) { + if (overwrite || serializer == null) + this.serializer = value; + return this; + } + + /** + * Sets the schema object that defines the format of the output. + * + * @param value The new value for this property. + * @return This object (for method chaining). + */ + public SerializedHeaderBuilder schema(HttpPartSchema value) { + this.schema = value; + return this; + } + + /** + * Creates the new {@link SerializedHeader} + * + * @return The new {@link SerializedHeader} + */ + public SerializedHeader build() { + return new SerializedHeader(this); + } + + @Override /* Headerable */ + public Header asHeader() { + return build(); + } + + @Override /* Headerable */ + public Header asNameValuePair() { + return build(); + } +} \ No newline at end of file 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 519471e..71da93f 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 @@ -48,8 +48,8 @@ public class SerializedNameValuePair implements NameValuePair, Headerable { * * @return A new builder for this object. */ - public static Builder create() { - return new Builder(); + public static SerializedNameValuePairBuilder create() { + return new SerializedNameValuePairBuilder(); } /** @@ -81,7 +81,7 @@ public class SerializedNameValuePair implements NameValuePair, Headerable { return new SerializedHeader(name, value, serializer, schema, skipIfEmpty); } - SerializedNameValuePair(Builder b) { + SerializedNameValuePair(SerializedNameValuePairBuilder b) { this.name = b.name; this.value = b.value; this.type = b.type; @@ -89,116 +89,6 @@ public class SerializedNameValuePair implements NameValuePair, Headerable { this.schema = b.schema == null ? HttpPartSchema.DEFAULT : b.schema; } - /** - * Builder for {@link SerializedNameValuePair} objects. - */ - public static class Builder { - String name; - Object value; - HttpPartType type; - HttpPartSerializerSession serializer; - HttpPartSchema schema; - - /** - * Sets the parameter name. - * - * @param value The new value for this property. - * @return This object (for method chaining). - */ - public Builder name(String value) { - this.name = value; - return this; - } - - /** - * Sets the POJO to serialize to the parameter value. - * - * @param value The new value for this property. - * @return This object (for method chaining). - */ - public Builder value(Object value) { - this.value = value; - return this; - } - - /** - * Sets the POJO to serialize to the parameter value. - * - * @param value The new value for this property. - * @return This object (for method chaining). - */ - public Builder value(Supplier<Object> value) { - this.value = value; - return this; - } - - /** - * Sets the HTTP part type. - * - * @param value The new value for this property. - * @return This object (for method chaining). - */ - public Builder type(HttpPartType value) { - this.type = value; - 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(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); - } - - /** - * Sets the serializer to use for serializing the value to a string value. - * - * @param value The new value for this property. - * @param overwrite If <jk>true</jk>, overwrites the existing value if the old value is <jk>null</jk>. - * @return This object (for method chaining). - */ - public Builder serializer(HttpPartSerializerSession value, boolean overwrite) { - if (overwrite || serializer == null) - this.serializer = value; - return this; - } - - /** - * Sets the schema object that defines the format of the output. - * - * @param value The new value for this property. - * @return This object (for method chaining). - */ - public Builder schema(HttpPartSchema value) { - this.schema = value; - return this; - } - - /** - * Creates the new {@link SerializedNameValuePair} - * - * @return The new {@link SerializedNameValuePair} - */ - public SerializedNameValuePair build() { - return new SerializedNameValuePair(this); - } - } - @Override /* NameValuePair */ public String getName() { return name; diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedNameValuePairBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedNameValuePairBuilder.java new file mode 100644 index 0000000..f51a5da --- /dev/null +++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedNameValuePairBuilder.java @@ -0,0 +1,138 @@ +// *************************************************************************************************************************** +// * 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 java.util.function.*; + +import org.apache.http.*; +import org.apache.juneau.httppart.*; + +/** + * Builder for {@link SerializedNameValuePair} objects. + */ +public class SerializedNameValuePairBuilder implements NameValuePairable, Headerable { + String name; + Object value; + HttpPartType type; + HttpPartSerializerSession serializer; + HttpPartSchema schema; + + /** + * Sets the parameter name. + * + * @param value The new value for this property. + * @return This object (for method chaining). + */ + public SerializedNameValuePairBuilder name(String value) { + this.name = value; + return this; + } + + /** + * Sets the POJO to serialize to the parameter value. + * + * @param value The new value for this property. + * @return This object (for method chaining). + */ + public SerializedNameValuePairBuilder value(Object value) { + this.value = value; + return this; + } + + /** + * Sets the POJO to serialize to the parameter value. + * + * @param value The new value for this property. + * @return This object (for method chaining). + */ + public SerializedNameValuePairBuilder value(Supplier<Object> value) { + this.value = value; + return this; + } + + /** + * Sets the HTTP part type. + * + * @param value The new value for this property. + * @return This object (for method chaining). + */ + public SerializedNameValuePairBuilder type(HttpPartType value) { + this.type = value; + 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 SerializedNameValuePairBuilder 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 SerializedNameValuePairBuilder serializer(HttpPartSerializerSession value) { + return serializer(value, true); + } + + /** + * Sets the serializer to use for serializing the value to a string value. + * + * @param value The new value for this property. + * @param overwrite If <jk>true</jk>, overwrites the existing value if the old value is <jk>null</jk>. + * @return This object (for method chaining). + */ + public SerializedNameValuePairBuilder serializer(HttpPartSerializerSession value, boolean overwrite) { + if (overwrite || serializer == null) + this.serializer = value; + return this; + } + + /** + * Sets the schema object that defines the format of the output. + * + * @param value The new value for this property. + * @return This object (for method chaining). + */ + public SerializedNameValuePairBuilder schema(HttpPartSchema value) { + this.schema = value; + return this; + } + + /** + * Creates the new {@link SerializedNameValuePair} + * + * @return The new {@link SerializedNameValuePair} + */ + public SerializedNameValuePair build() { + return new SerializedNameValuePair(this); + } + + @Override /* NameValuePairable */ + public NameValuePair asNameValuePair() { + return build(); + } + + @Override /* Headerable */ + public Header asHeader() { + return build().asHeader(); + } +} \ No newline at end of file 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 cbc1674..f5fb62f 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 @@ -15,11 +15,16 @@ package org.apache.juneau.http.header; import static org.apache.juneau.internal.StringUtils.*; import java.io.*; +import java.util.*; import java.util.function.*; import org.apache.http.*; import org.apache.http.message.*; +import org.apache.juneau.*; import org.apache.juneau.annotation.*; +import org.apache.juneau.http.*; +import org.apache.juneau.http.header.BasicHeader; +import org.apache.juneau.reflect.*; /** * Superclass of all headers defined in this package. @@ -75,6 +80,41 @@ public class BasicHeader implements Header, Cloneable, Serializable { } /** + * Utility method for converting an arbitrary object to a {@link Header}. + * + * @param o + * The object to cast or convert to a {@link Header}. + * @return Either the same object cast as a {@link Header} or converted to a {@link Header}. + */ + @SuppressWarnings("rawtypes") + public static Header cast(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); + if (o instanceof NameValuePairable) + return BasicHeader.of(((NameValuePairable)o).asNameValuePair()); + if (o instanceof Map.Entry) { + Map.Entry e = (Map.Entry)o; + return BasicHeader.of(stringify(e.getKey()), e.getValue()); + } + throw new BasicRuntimeException("Object of type {0} could not be converted to a Header.", o == null ? null : o.getClass().getName()); + } + + /** + * Returns <jk>true</jk> if the {@link #cast(Object)} method can be used on the specified object. + * + * @param o The object to check. + * @return <jk>true</jk> if the {@link #cast(Object)} method can be used on the specified object. + */ + public static boolean canCast(Object o) { + ClassInfo ci = ClassInfo.of(o); + return ci != null && ci.isChildOfAny(Header.class, Headerable.class, NameValuePair.class, NameValuePairable.class, Map.Entry.class); + } + + /** * Constructor. * * @param name The parameter name. 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 e1e17b4..a02e0bd 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 @@ -6597,7 +6597,7 @@ public class RestClientTest { ; fail(); } catch (RestCallException e) { - assertEquals("Invalid type passed to path(): java.lang.String", e.getMessage()); + assertEquals("Invalid type passed to paths(): java.lang.String", e.getMessage()); } try { MockRestClient 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 1a76f8b..0b0a81f 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 @@ -55,8 +55,7 @@ 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.header.*; import org.apache.juneau.http.remote.*; import org.apache.juneau.httppart.*; import org.apache.juneau.httppart.bean.*; @@ -1983,35 +1982,46 @@ public class RestClient extends BeanContext implements HttpClient, Closeable, Re HttpPartSerializerSession partSerializerSession = partSerializer.createPartSession(null); - Function<Object,Object> f = new Function<Object,Object>() { + Function<Object,Object> headerFunction = 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; + if (x instanceof SerializedHeaderBuilder) + x = ((SerializedHeaderBuilder)x).serializer(partSerializerSession, false).build(); + else if (x instanceof SerializedNameValuePairBuilder) + x = ((SerializedNameValuePairBuilder)x).serializer(partSerializerSession, false).build(); + return BasicHeader.cast(x); + } + }; + + Function<Object,Object> nameValuePairFunction = new Function<Object,Object>() { + @Override + public Object apply(Object x) { + if (x instanceof SerializedNameValuePairBuilder) + x = ((SerializedNameValuePairBuilder)x).serializer(partSerializerSession, false).build(); + if (x instanceof SerializedHeaderBuilder) + x = ((SerializedHeaderBuilder)x).serializer(partSerializerSession, false).build(); + return BasicNameValuePair.cast(x); } }; this.headers = Collections.unmodifiableList( getListProperty(RESTCLIENT_headers, Object.class) .stream() - .map(f) + .map(headerFunction) .collect(Collectors.toList()) ); this.query = Collections.unmodifiableList( getListProperty(RESTCLIENT_query, Object.class) .stream() - .map(f) + .map(nameValuePairFunction) .collect(Collectors.toList()) ); this.formData = Collections.unmodifiableList( getListProperty(RESTCLIENT_formData, Object.class) .stream() - .map(f) + .map(nameValuePairFunction) .collect(Collectors.toList()) ); @@ -2849,13 +2859,13 @@ public class RestClient extends BeanContext implements HttpClient, Closeable, Re RestRequest req = createRequest(toURI(url, rootUrl), method.toUpperCase(Locale.ENGLISH), hasBody); for (Object o : headers) - req.header(toHeader(o)); + req.header(BasicHeader.cast(o)); for (Object o : query) - req.query(toNameValuePair(o)); + req.query(BasicNameValuePair.cast(o)); for (Object o : formData) - req.formData(toNameValuePair(o)); + req.formData(BasicNameValuePair.cast(o)); onInit(req); @@ -3701,22 +3711,6 @@ 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 f9effa6..6c55d2a 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,11 +48,9 @@ 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.*; -import org.apache.juneau.collections.*; import org.apache.juneau.html.*; import org.apache.juneau.http.*; import org.apache.juneau.http.header.*; @@ -1298,47 +1296,42 @@ public class RestClientBuilder extends BeanContextBuilder { * .build(); * </p> * - * <p> - * Can be any of the following singleton types: - * <ul> - * <li>{@link Header} (including any subclasses such as {@link Accept}) - * <li>{@link NameValuePair} - * </ul> - * - * <p> - * Can also be any of the following collection types: - * <ul> - * <li>{@link Map} / {@link OMap} + * @param headers + * The header to set. + * <br>Can be any of the following types: * <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. + * <li>{@link Header} (including any subclasses such as {@link Accept}) + * <li>{@link NameValuePair} + * <li>{@link Headerable} + * <li>{@link NameValuePairable} + * <li>{@link java.util.Map.Entry} + * <li>{@link NameValuePairs} + * <li>{@link Map} + * <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>A collection or array of anything on this list. * </ul> - * <li>{@link NameValuePairs} - * </ul> - * - * @param headers The header to set. * @return This object (for method chaining). */ - @SuppressWarnings("rawtypes") @FluentSetter public RestClientBuilder headers(Object...headers) { for (Object h : headers) { - if (h instanceof Header || h instanceof SerializedHeader.Builder || h instanceof SerializedNameValuePair.Builder) + if (BasicHeader.canCast(h)) { 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()) + for (Map.Entry<Object,Object> e : toMap(h).entrySet()) appendTo(RESTCLIENT_headers, serializedHeader(e.getKey(), e.getValue(), null, null)); - } else if (h instanceof NameValuePairs) { - for (NameValuePair p : (NameValuePairs)h) - headers(p); + } else if (h instanceof Collection) { + for (Object o : (Collection<?>)h) + headers(o); + } else if (h != null && h.getClass().isArray()) { + for (int i = 0; i < Array.getLength(h); i++) + headers(Array.get(h, i)); } else if (h != null) { - throw new RuntimeException("Invalid type passed to headers(): " + h.getClass().getName()); + throw new RuntimeException("Invalid type passed to headers(): " + className(h)); } } return this; @@ -2053,42 +2046,41 @@ public class RestClientBuilder extends BeanContextBuilder { * .queries(BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>, <js>"bar"</js>)) * .build(); * </p> - * - * <p> - * Can be any of the following singleton types: - * <ul> - * <li>{@link NameValuePair} - * </ul> - * - * <p> - * Can be any of the following collection types: - * <ul> - * <li>{@link Map} / {@link OMap} + * + * @param params + * The query parameters. + * <br>Can be any of the following types: * <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. + * <li>{@link NameValuePair} + * <li>{@link NameValuePairable} + * <li>{@link java.util.Map.Entry} + * <li>{@link NameValuePairs} + * <li>{@link Map} + * <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>A collection or array of anything on this list. * </ul> - * <li>{@link NameValuePairs} - * </ul> - - * @param params The query parameters. * @return This object (for method chaining). */ - @SuppressWarnings("rawtypes") @FluentSetter public RestClientBuilder queries(Object...params) { for (Object p : params) { - if (p instanceof NameValuePair || p instanceof SerializedNameValuePair.Builder) { + if (BasicNameValuePair.canCast(p)) { appendTo(RESTCLIENT_query, p); } else if (p instanceof Map) { - for (Map.Entry e : toMap(p).entrySet()) + for (Map.Entry<Object,Object> 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) - appendTo(RESTCLIENT_query, nvp); + } else if (p instanceof Collection) { + for (Object o : (Collection<?>)p) + queries(o); + } else if (p != null && p.getClass().isArray()) { + for (int i = 0; i < Array.getLength(p); i++) + queries(Array.get(p, i)); } else if (p != null) { - throw new RuntimeException("Invalid type passed to query(): " + p.getClass().getName()); + throw new RuntimeException("Invalid type passed to query(): " + className(p)); } } return this; @@ -2342,40 +2334,40 @@ public class RestClientBuilder extends BeanContextBuilder { * .build(); * </p> * - * <p> - * Can be any of the following singleton types: - * <ul> - * <li>{@link NameValuePair} - * </ul> - * - * <p> - * Can be any of the following collection types: - * <ul> - * <li>{@link Map} / {@link OMap} + * @param params + * The form-data parameters. + * <br>Can be any of the following types: * <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. + * <li>{@link NameValuePair} + * <li>{@link NameValuePairable} + * <li>{@link java.util.Map.Entry} + * <li>{@link NameValuePairs} + * <li>{@link Map} + * <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>A collection or array of anything on this list. * </ul> - * <li>{@link NameValuePairs} - * </ul> - * - * @param params The form-data parameter. * @return This object (for method chaining). */ @FluentSetter public RestClientBuilder formDatas(Object...params) { for (Object p : params) { - if (p instanceof NameValuePair || p instanceof SerializedNameValuePair.Builder) { + if (BasicNameValuePair.canCast(p)) { appendTo(RESTCLIENT_formData, p); } else if (p instanceof Map) { 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) - appendTo(RESTCLIENT_formData, nvp); + } else if (p instanceof Collection) { + for (Object o : (Collection<?>)p) + formDatas(o); + } else if (p != null && p.getClass().isArray()) { + for (int i = 0; i < Array.getLength(p); i++) + formDatas(Array.get(p, i)); } else if (p != null) { - throw new RuntimeException("Invalid type passed to formData(): " + p.getClass().getName()); + throw new RuntimeException("Invalid type passed to formData(): " + className(p)); } } return this; @@ -5818,11 +5810,14 @@ public class RestClientBuilder extends BeanContextBuilder { return (Map<Object,Object>)o; } - private static SerializedNameValuePair.Builder serializedNameValuePair(Object key, Object value, HttpPartType type, HttpPartSerializer serializer, HttpPartSchema schema) { + private static SerializedNameValuePairBuilder 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) { + private static SerializedHeaderBuilder serializedHeader(Object key, Object value, HttpPartSerializer serializer, HttpPartSchema schema) { return SerializedHeader.create().name(stringify(key)).value(value).serializer(serializer).schema(schema); } + private static String className(Object value) { + return value == null ? null : value.getClass().getName(); + } } 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 08380bc..7db63b2 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 @@ -17,6 +17,7 @@ import static org.apache.juneau.AddFlag.*; import static org.apache.juneau.httppart.HttpPartType.*; import java.io.*; +import java.lang.reflect.*; import java.net.*; import java.text.*; import java.util.*; @@ -32,13 +33,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.*; @@ -945,23 +946,36 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * .run(); * </p> * - * @param params The path parameters to set. + * @param params + * The path parameters to set. * <br>Can be any of the following types: * <ul> - * <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> + * <li>{@link NameValuePair} + * <li>{@link NameValuePairable} + * <li>{@link java.util.Map.Entry} + * <li>{@link NameValuePairs} + * <li>{@link Map} + * <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>A collection or array of anything on this list. + * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ @SuppressWarnings("rawtypes") public RestRequest paths(Object...params) throws RestCallException { for (Object o : params) { - if (o instanceof NameValuePair) { - innerPath((NameValuePair)o); - } else if (o instanceof NameValuePairs) { - for (NameValuePair p : (NameValuePairs)o) - innerPath(p); + if (BasicNameValuePair.canCast(o)) { + innerPath(BasicNameValuePair.cast(o)); + } else if (o instanceof Collection) { + for (Object o2 : (Collection<?>)o) + innerPath(BasicNameValuePair.cast(o2)); + } else if (o != null && o.getClass().isArray()) { + for (int i = 0; i < Array.getLength(o); i++) + innerPath(BasicNameValuePair.cast(Array.get(o, i))); } else if (o instanceof Map) { for (Map.Entry e : toMap(o).entrySet()) innerPath(serializedNameValuePair(e.getKey(), e.getValue(), PATH, partSerializer, null, null)); @@ -969,7 +983,7 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur for (Map.Entry<String,Object> e : toBeanMap(o).entrySet()) innerPath(serializedNameValuePair(e.getKey(), e.getValue(), PATH, partSerializer, null, null)); } else { - throw new RestCallException("Invalid type passed to path(): " + o.getClass().getName()); + throw new RestCallException("Invalid type passed to paths(): " + className(o)); } } return this; @@ -1013,9 +1027,14 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur if (! isMulti) return innerPath(serializedNameValuePair(name, value, PATH, serializer, schema, null)); - if (value instanceof NameValuePairs) { - for (NameValuePair p : (NameValuePairs)value) - innerPath(p); + if (BasicNameValuePair.canCast(value)) { + innerPath(BasicNameValuePair.cast(value)); + } else if (value instanceof Collection) { + for (Object o : (Collection<?>)value) + innerPath(BasicNameValuePair.cast(o)); + } else if (value != null && value.getClass().isArray()) { + for (int i = 0; i < Array.getLength(value); i++) + innerPath(BasicNameValuePair.cast(Array.get(value, i))); } else if (value instanceof Map) { for (Map.Entry<Object,Object> p : toMap(value).entrySet()) innerPath(serializedNameValuePair(p.getKey(), p.getValue(), PATH, serializer, schema, null)); @@ -1215,12 +1234,22 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * .run(); * </p> * - * @param params The parameters to set. + * @param params + * The parameters to set. * <br>Can be any of the following types: * <ul> - * <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> + * <li>{@link NameValuePair} + * <li>{@link NameValuePairable} + * <li>{@link java.util.Map.Entry} + * <li>{@link NameValuePairs} + * <li>{@link Map} + * <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>A collection or array of anything on this list. + * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ @@ -1251,22 +1280,36 @@ 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 params The parameters to set. + * @param params + * The parameters to set. * <br>Can be any of the following types: * <ul> - * <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> + * <li>{@link NameValuePair} + * <li>{@link NameValuePairable} + * <li>{@link java.util.Map.Entry} + * <li>{@link NameValuePairs} + * <li>{@link Map} + * <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>A collection or array of anything on this list. + * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ public RestRequest queries(EnumSet<AddFlag> flags, Object...params) throws RestCallException { List<NameValuePair> l = new ArrayList<>(); for (Object o : params) { - if (o instanceof NameValuePair) { - l.add((NameValuePair)o); - } else if (o instanceof NameValuePairs) { - l.addAll((NameValuePairs)o); + if (BasicNameValuePair.canCast(o)) { + l.add(BasicNameValuePair.cast(o)); + } else if (o instanceof Collection) { + for (Object o2 : (Collection<?>)o) + l.add(BasicNameValuePair.cast(o2)); + } else if (o != null && o.getClass().isArray()) { + for (int i = 0; i < Array.getLength(o); i++) + l.add(BasicNameValuePair.cast(Array.get(o, i))); } else if (o instanceof Map) { for (Map.Entry<Object,Object> e : toMap(o).entrySet()) l.add(serializedNameValuePair(e.getKey(), e.getValue(), QUERY, partSerializer, null, null)); @@ -1274,7 +1317,7 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur for (Map.Entry<String,Object> e : toBeanMap(o).entrySet()) l.add(serializedNameValuePair(e.getKey(), e.getValue(), QUERY, partSerializer, null, null)); } else { - throw new RestCallException("Invalid type passed to queries(): " + o.getClass().getName()); + throw new RestCallException("Invalid type passed to queries(): " + className(o)); } } return innerQuery(flags, l); @@ -1361,8 +1404,14 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur List<NameValuePair> l = AList.of(); - if (value instanceof NameValuePairs) { - l.addAll((NameValuePairs)value); + if (BasicNameValuePair.canCast(value)) { + l.add(BasicNameValuePair.cast(value)); + } else if (value instanceof Collection) { + for (Object o : (Collection<?>)value) + l.add(BasicNameValuePair.cast(o)); + } else if (value != null && value.getClass().isArray()) { + for (int i = 0; i < Array.getLength(value); i++) + l.add(BasicNameValuePair.cast(Array.get(value, i))); } else if (value instanceof Map) { for (Map.Entry<Object,Object> e : toMap(value).entrySet()) l.add(serializedNameValuePair(e.getKey(), e.getValue(), QUERY, serializer, schema, flags)); @@ -1577,12 +1626,22 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * .run(); * </p> * - * @param params The parameters to set. + * @param params + * The parameters to set. * <br>Can be any of the following types: * <ul> - * <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> + * <li>{@link NameValuePair} + * <li>{@link NameValuePairable} + * <li>{@link java.util.Map.Entry} + * <li>{@link NameValuePairs} + * <li>{@link Map} + * <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>A collection or array of anything on this list. + * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ @@ -1613,22 +1672,36 @@ 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 params The parameters to set. + * @param params + * The parameters to set. * <br>Can be any of the following types: * <ul> - * <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> + * <li>{@link NameValuePair} + * <li>{@link NameValuePairable} + * <li>{@link java.util.Map.Entry} + * <li>{@link NameValuePairs} + * <li>{@link Map} + * <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>A collection or array of anything on this list. + * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ public RestRequest formDatas(EnumSet<AddFlag> flags, Object...params) throws RestCallException { List<NameValuePair> l = new ArrayList<>(); for (Object o : params) { - if (o instanceof NameValuePair) { - l.add((NameValuePair)o); - } else if (o instanceof NameValuePairs) { - l.addAll((NameValuePairs)o); + if (BasicNameValuePair.canCast(o)) { + l.add(BasicNameValuePair.cast(o)); + } else if (o instanceof Collection) { + for (Object o2 : (Collection<?>)o) + l.add(BasicNameValuePair.cast(o2)); + } else if (o != null && o.getClass().isArray()) { + for (int i = 0; i < Array.getLength(o); i++) + l.add(BasicNameValuePair.cast(Array.get(o, i))); } else if (o instanceof Map) { for (Map.Entry<Object,Object> e : toMap(o).entrySet()) l.add(serializedNameValuePair(e.getKey(), e.getValue(), FORMDATA, partSerializer, null, flags)); @@ -1636,7 +1709,7 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur for (Map.Entry<String,Object> e : toBeanMap(o).entrySet()) l.add(serializedNameValuePair(e.getKey(), e.getValue(), FORMDATA, partSerializer, null, flags)); } else { - throw new RestCallException("Invalid type passed to formDatas(): " + o.getClass().getName()); + throw new RestCallException("Invalid type passed to formDatas(): " + className(o)); } } return innerFormData(flags, l); @@ -1734,8 +1807,14 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur List<NameValuePair> l = AList.of(); - if (value instanceof NameValuePairs) { - l.addAll((NameValuePairs)value); + if (BasicNameValuePair.canCast(value)) { + l.add(BasicNameValuePair.cast(value)); + } else if (value instanceof Collection) { + for (Object o : (Collection<?>)value) + l.add(BasicNameValuePair.cast(o)); + } else if (value != null && value.getClass().isArray()) { + for (int i = 0; i < Array.getLength(value); i++) + l.add(BasicNameValuePair.cast(Array.get(value, i))); } else if (value instanceof Map) { for (Map.Entry<Object,Object> e : toMap(value).entrySet()) l.add(serializedNameValuePair(e.getKey(), e.getValue(), FORMDATA, serializer, schema, flags)); @@ -2077,12 +2156,24 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur * .run(); * </p> * - * @param headers The headers to set. + * @param headers + * The headers to set. * <br>Can be any of the following types: * <ul> - * <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> + * <li>{@link Header} (including any subclasses such as {@link Accept}) + * <li>{@link NameValuePair} + * <li>{@link Headerable} + * <li>{@link NameValuePairable} + * <li>{@link java.util.Map.Entry} + * <li>{@link NameValuePairs} + * <li>{@link Map} + * <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>A collection or array of anything on this list. + * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ @@ -2113,23 +2204,38 @@ 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 headers to set. + * @param headers + * The headers to set. * <br>Can be any of the following types: * <ul> - * <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> + * <li>{@link Header} (including any subclasses such as {@link Accept}) + * <li>{@link NameValuePair} + * <li>{@link Headerable} + * <li>{@link NameValuePairable} + * <li>{@link java.util.Map.Entry} + * <li>{@link NameValuePairs} + * <li>{@link Map} + * <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>A collection or array of anything on this list. + * </ul> * @return This object (for method chaining). * @throws RestCallException Invalid input. */ public RestRequest headers(EnumSet<AddFlag> flags, Object...headers) throws RestCallException { List<Header> l = new ArrayList<>(); for (Object o : headers) { - if (o instanceof Header || o instanceof NameValuePair) { - l.add(toHeader(o)); - } else if (o instanceof NameValuePairs) { - for (NameValuePair p : (NameValuePairs)o) - l.add(toHeader(p)); + if (BasicHeader.canCast(o)) { + l.add(BasicHeader.cast(o)); + } else if (o instanceof Collection) { + for (Object o2 : (Collection<?>)o) + l.add(BasicHeader.cast(o2)); + } else if (o != null && o.getClass().isArray()) { + for (int i = 0; i < Array.getLength(o); i++) + l.add(BasicHeader.cast(Array.get(o, i))); } else if (o instanceof Map) { for (Map.Entry<Object,Object> e : toMap(o).entrySet()) l.add(serializedHeader(e.getKey(), e.getValue(), partSerializer, null, flags)); @@ -2183,11 +2289,14 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur List<Header> l = AList.of(); - if (value instanceof Headerable) { - l.add(((Headerable)value).asHeader()); - } else if (value instanceof NameValuePairs) { - for (NameValuePair p : (NameValuePairs)value) - l.add(toHeader(p)); + if (BasicHeader.canCast(value)) { + l.add(BasicHeader.cast(value)); + } else if (value instanceof Collection) { + for (Object o : (Collection<?>)value) + l.add(BasicHeader.cast(o)); + } else if (value != null && value.getClass().isArray()) { + for (int i = 0; i < Array.getLength(value); i++) + l.add(BasicHeader.cast(Array.get(value, i))); } else if (value instanceof Map) { for (Map.Entry<Object,Object> e : toMap(value).entrySet()) l.add(serializedHeader(e.getKey(), e.getValue(), serializer, schema, flags)); @@ -3323,16 +3432,6 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur 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(); }