Repository: incubator-juneau
Updated Branches:
  refs/heads/master a3d7cc9af -> 3c1ff80f9


Support for @Query("*") and @Path on remoteable interfaces.

Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/3c1ff80f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/3c1ff80f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/3c1ff80f

Branch: refs/heads/master
Commit: 3c1ff80f95a441a0358b403f9a4a9cb8e70f5209
Parents: a3d7cc9
Author: JamesBognar <[email protected]>
Authored: Sun May 21 05:01:21 2017 -0400
Committer: JamesBognar <[email protected]>
Committed: Sun May 21 05:01:21 2017 -0400

----------------------------------------------------------------------
 .../java/org/apache/juneau/BeanContext.java     |  12 +
 .../org/apache/juneau/remoteable/FormData.java  |  13 +-
 .../apache/juneau/remoteable/FormDataIfNE.java  |  11 +-
 .../org/apache/juneau/remoteable/Header.java    |  14 +-
 .../apache/juneau/remoteable/HeaderIfNE.java    |  11 +-
 .../java/org/apache/juneau/remoteable/Path.java |  63 ++++++
 .../org/apache/juneau/remoteable/Query.java     |  15 +-
 .../org/apache/juneau/remoteable/QueryIfNE.java |  12 +-
 .../juneau/remoteable/RemoteableMethodMeta.java |  17 +-
 juneau-core/src/main/javadoc/overview.html      |   6 +
 .../org/apache/juneau/rest/client/RestCall.java | 226 +++++++++++++------
 .../apache/juneau/rest/client/RestClient.java   |   5 +
 .../rest/test/ThirdPartyProxyResource.java      |  92 ++++++++
 .../juneau/rest/test/ThirdPartyProxyTest.java   |  93 ++++++++
 14 files changed, 505 insertions(+), 85 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/3c1ff80f/juneau-core/src/main/java/org/apache/juneau/BeanContext.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/BeanContext.java 
b/juneau-core/src/main/java/org/apache/juneau/BeanContext.java
index 33c1165..5b1f166 100644
--- a/juneau-core/src/main/java/org/apache/juneau/BeanContext.java
+++ b/juneau-core/src/main/java/org/apache/juneau/BeanContext.java
@@ -1000,6 +1000,18 @@ public class BeanContext extends Context {
        }
 
        /**
+        * Returns <jk>true</jk> if the specified object is a bean.
+        *
+        * @param o The object to test.
+        * @return <jk>true</jk> if the specified object is a bean.  
<jk>false</jk> if the bean is <jk>null</jk>.
+        */
+       public boolean isBean(Object o) {
+               if (o == null)
+                       return false;
+               return getClassMetaForObject(o).isBean();
+       }
+
+       /**
         * Prints meta cache statistics to <code>System.out</code>.
         */
        protected static void dumpCacheStats() {

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/3c1ff80f/juneau-core/src/main/java/org/apache/juneau/remoteable/FormData.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/remoteable/FormData.java 
b/juneau-core/src/main/java/org/apache/juneau/remoteable/FormData.java
index 5d0ecf2..780e64d 100644
--- a/juneau-core/src/main/java/org/apache/juneau/remoteable/FormData.java
+++ b/juneau-core/src/main/java/org/apache/juneau/remoteable/FormData.java
@@ -44,6 +44,8 @@ import org.apache.juneau.urlencoding.*;
  *     <li><code>NameValuePairs</code> - Individual name-value pairs.
  *     <li><code>Map&lt;String,Object&gt;</code> - Individual name-value pairs.
  *             Values are converted to text using {@link 
UrlEncodingSerializer#serializePart(Object, Boolean, Boolean)}.
+ *     <li>A bean - Individual name-value pairs.
+ *             Values are converted to text using {@link 
UrlEncodingSerializer#serializePart(Object, Boolean, Boolean)}.
  * </ul>
  */
 @Documented
@@ -54,7 +56,14 @@ public @interface FormData {
 
        /**
         * The form post parameter name.
-        * Can be blank if the value is an instance of 
<code>NameValuePairs</code> or <code>Map&lt;String,Object&gt;</code>.
+        * <p>
+        * A value of <js>"*"</js> indicates the value should be serialized as 
name/value pairs and is applicable
+        * for the following data types:
+        * <ul>
+        *      <li><code>NameValuePairs</code>
+        *      <li><code>Map&lt;String,Object&gt;</code>
+        *      <li>A bean
+        * </ul>
         */
-       String value() default "";
+       String value() default "*";
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/3c1ff80f/juneau-core/src/main/java/org/apache/juneau/remoteable/FormDataIfNE.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/remoteable/FormDataIfNE.java 
b/juneau-core/src/main/java/org/apache/juneau/remoteable/FormDataIfNE.java
index a156928..e38ac6a 100644
--- a/juneau-core/src/main/java/org/apache/juneau/remoteable/FormDataIfNE.java
+++ b/juneau-core/src/main/java/org/apache/juneau/remoteable/FormDataIfNE.java
@@ -28,7 +28,14 @@ public @interface FormDataIfNE {
 
        /**
         * The form post parameter name.
-        * Can be blank if the value is an instance of 
<code>NameValuePairs</code> or <code>Map&lt;String,Object&gt;</code>.
+        * <p>
+        * A value of <js>"*"</js> indicates the value should be serialized as 
name/value pairs and is applicable
+        * for the following data types:
+        * <ul>
+        *      <li><code>NameValuePairs</code>
+        *      <li><code>Map&lt;String,Object&gt;</code>
+        *      <li>A bean
+        * </ul>
         */
-       String value() default "";
+       String value() default "*";
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/3c1ff80f/juneau-core/src/main/java/org/apache/juneau/remoteable/Header.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/remoteable/Header.java 
b/juneau-core/src/main/java/org/apache/juneau/remoteable/Header.java
index 31eab82..d414eb1 100644
--- a/juneau-core/src/main/java/org/apache/juneau/remoteable/Header.java
+++ b/juneau-core/src/main/java/org/apache/juneau/remoteable/Header.java
@@ -37,9 +37,12 @@ import org.apache.juneau.urlencoding.*;
  * <p>
  * The argument can be any of the following types:
  * <ul class='spaced-list'>
+ *     <li><code>NameValuePairs</code> - Individual name-value pairs.
  *     <li>Any serializable POJO - Converted to text using {@link 
UrlEncodingSerializer#serializePart(Object, Boolean, Boolean)}.
  *     <li><code>Map&lt;String,Object&gt;</code> - Individual name-value pairs.
  *             Values are converted to text using {@link 
UrlEncodingSerializer#serializePart(Object, Boolean, Boolean)}.
+ *     <li>A bean - Individual name-value pairs.
+ *             Values are converted to text using {@link 
UrlEncodingSerializer#serializePart(Object, Boolean, Boolean)}.
  * </ul>
  */
 @Documented
@@ -50,7 +53,14 @@ public @interface Header {
 
        /**
         * The HTTP header name.
-        * Can be blank if the value is an instance of 
<code>Map&lt;String,Object&gt;</code>.
+        * <p>
+        * A value of <js>"*"</js> indicates the value should be serialized as 
name/value pairs and is applicable
+        * for the following data types:
+        * <ul>
+        *      <li><code>NameValuePairs</code>
+        *      <li><code>Map&lt;String,Object&gt;</code>
+        *      <li>A bean
+        * </ul>
         */
-       String value() default "";
+       String value() default "*";
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/3c1ff80f/juneau-core/src/main/java/org/apache/juneau/remoteable/HeaderIfNE.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/remoteable/HeaderIfNE.java 
b/juneau-core/src/main/java/org/apache/juneau/remoteable/HeaderIfNE.java
index e99915e..350ddcf 100644
--- a/juneau-core/src/main/java/org/apache/juneau/remoteable/HeaderIfNE.java
+++ b/juneau-core/src/main/java/org/apache/juneau/remoteable/HeaderIfNE.java
@@ -28,7 +28,14 @@ public @interface HeaderIfNE {
 
        /**
         * The HTTP header name.
-        * Can be blank if the value is an instance of 
<code>Map&lt;String,Object&gt;</code>.
+        * <p>
+        * A value of <js>"*"</js> indicates the value should be serialized as 
name/value pairs and is applicable
+        * for the following data types:
+        * <ul>
+        *      <li><code>NameValuePairs</code>
+        *      <li><code>Map&lt;String,Object&gt;</code>
+        *      <li>A bean
+        * </ul>
         */
-       String value();
+       String value() default "*";
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/3c1ff80f/juneau-core/src/main/java/org/apache/juneau/remoteable/Path.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/remoteable/Path.java 
b/juneau-core/src/main/java/org/apache/juneau/remoteable/Path.java
new file mode 100644
index 0000000..0420e54
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/remoteable/Path.java
@@ -0,0 +1,63 @@
+// 
***************************************************************************************************************************
+// * 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.remoteable;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
+import org.apache.juneau.urlencoding.*;
+
+/**
+ * Annotation applied to Java method arguments of interface proxies to denote 
that they are path variables on the request.
+ * <p>
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode'>
+ *     <ja>@Remoteable</ja>(path=<js>"/myproxy"</js>)
+ *     <jk>public interface</jk> MyProxy {
+ *
+ *             <ja>@RemoteMethod</ja>(path=<js>"/mymethod1/{foo}"</js>)
+ *             String myProxyMethod1(<ja>@Path</ja>(<js>"foo"</js>)</ja> 
String foo);
+ *     }
+ * </p>
+ * <p>
+ * The argument can be any of the following types:
+ * <ul class='spaced-list'>
+ *     <li><code>NameValuePairs</code> - Individual name-value pairs.
+ *     <li>Any serializable POJO - Converted to text using {@link 
UrlEncodingSerializer#serializePart(Object, Boolean, Boolean)}.
+ *     <li><code>Map&lt;String,Object&gt;</code> - Individual name-value pairs.
+ *             Values are converted to text using {@link 
UrlEncodingSerializer#serializePart(Object, Boolean, Boolean)}.
+ *     <li>A bean - Individual name-value pairs.
+ *             Values are converted to text using {@link 
UrlEncodingSerializer#serializePart(Object, Boolean, Boolean)}.
+ * </ul>
+*/
+@Documented
+@Target(PARAMETER)
+@Retention(RUNTIME)
+@Inherited
+public @interface Path {
+
+       /**
+        * The path parameter name.
+        * <p>
+        * A value of <js>"*"</js> indicates the value should be serialized as 
name/value pairs and is applicable
+        * for the following data types:
+        * <ul>
+        *      <li><code>NameValuePairs</code>
+        *      <li><code>Map&lt;String,Object&gt;</code>
+        *      <li>A bean
+        * </ul>
+        */
+       String value() default "*";
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/3c1ff80f/juneau-core/src/main/java/org/apache/juneau/remoteable/Query.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/remoteable/Query.java 
b/juneau-core/src/main/java/org/apache/juneau/remoteable/Query.java
index 0a82529..bd7e4e7 100644
--- a/juneau-core/src/main/java/org/apache/juneau/remoteable/Query.java
+++ b/juneau-core/src/main/java/org/apache/juneau/remoteable/Query.java
@@ -40,9 +40,12 @@ import org.apache.juneau.urlencoding.*;
  * <p>
  * The argument can be any of the following types:
  * <ul class='spaced-list'>
+ *     <li><code>NameValuePairs</code> - Individual name-value pairs.
  *     <li>Any serializable POJO - Converted to text using {@link 
UrlEncodingSerializer#serializePart(Object, Boolean, Boolean)}.
  *     <li><code>Map&lt;String,Object&gt;</code> - Individual name-value pairs.
  *             Values are converted to text using {@link 
UrlEncodingSerializer#serializePart(Object, Boolean, Boolean)}.
+ *     <li>A bean - Individual name-value pairs.
+ *             Values are converted to text using {@link 
UrlEncodingSerializer#serializePart(Object, Boolean, Boolean)}.
  *     <li>{@link String} - Treated as a query string.
  * </ul>
 */
@@ -54,7 +57,15 @@ public @interface Query {
 
        /**
         * The query parameter name.
-        * Can be blank if the value is an instance of 
<code>Map&lt;String,Object&gt;</code> or <code>String</code>.
+        * <p>
+        * A value of <js>"*"</js> indicates the value should be serialized as 
name/value pairs and is applicable
+        * for the following data types:
+        * <ul>
+        *      <li><code>String</code> - A complete query string.
+        *      <li><code>NameValuePairs</code>
+        *      <li><code>Map&lt;String,Object&gt;</code>
+        *      <li>A bean
+        * </ul>
         */
-       String value() default "";
+       String value() default "*";
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/3c1ff80f/juneau-core/src/main/java/org/apache/juneau/remoteable/QueryIfNE.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/remoteable/QueryIfNE.java 
b/juneau-core/src/main/java/org/apache/juneau/remoteable/QueryIfNE.java
index 10ae263..59ac3d2 100644
--- a/juneau-core/src/main/java/org/apache/juneau/remoteable/QueryIfNE.java
+++ b/juneau-core/src/main/java/org/apache/juneau/remoteable/QueryIfNE.java
@@ -28,7 +28,15 @@ public @interface QueryIfNE {
 
        /**
         * The query parameter name.
-        * Can be blank if the value is an instance of 
<code>Map&lt;String,Object&gt;</code> or <code>String</code>.
+        * <p>
+        * A value of <js>"*"</js> indicates the value should be serialized as 
name/value pairs and is applicable
+        * for the following data types:
+        * <ul>
+        *      <li><code>String</code> - A complete query string.
+        *      <li><code>NameValuePairs</code>
+        *      <li><code>Map&lt;String,Object&gt;</code>
+        *      <li>A bean
+        * </ul>
         */
-       String value();
+       String value() default "*";
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/3c1ff80f/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteableMethodMeta.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteableMethodMeta.java
 
b/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteableMethodMeta.java
index 12b0d6b..d48d42f 100644
--- 
a/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteableMethodMeta.java
+++ 
b/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteableMethodMeta.java
@@ -29,7 +29,7 @@ public class RemoteableMethodMeta {
 
        private final String httpMethod;
        private final String url;
-       private final RemoteMethodArg[] queryArgs, headerArgs, formDataArgs;
+       private final RemoteMethodArg[] pathArgs, queryArgs, headerArgs, 
formDataArgs;
        private final Integer[] otherArgs;
        private final Integer bodyArg;
 
@@ -43,6 +43,7 @@ public class RemoteableMethodMeta {
                Builder b = new Builder(restUrl, m);
                this.httpMethod = b.httpMethod;
                this.url = b.url;
+               this.pathArgs = b.pathArgs.toArray(new 
RemoteMethodArg[b.pathArgs.size()]);
                this.queryArgs = b.queryArgs.toArray(new 
RemoteMethodArg[b.queryArgs.size()]);
                this.formDataArgs = b.formDataArgs.toArray(new 
RemoteMethodArg[b.formDataArgs.size()]);
                this.headerArgs = b.headerArgs.toArray(new 
RemoteMethodArg[b.headerArgs.size()]);
@@ -53,6 +54,7 @@ public class RemoteableMethodMeta {
        private static class Builder {
                private String httpMethod, url;
                private List<RemoteMethodArg>
+                       pathArgs = new LinkedList<RemoteMethodArg>(),
                        queryArgs = new LinkedList<RemoteMethodArg>(),
                        headerArgs = new LinkedList<RemoteMethodArg>(),
                        formDataArgs = new LinkedList<RemoteMethodArg>();
@@ -83,7 +85,10 @@ public class RemoteableMethodMeta {
                                boolean annotated = false;
                                for (Annotation a : aa) {
                                        Class<?> ca = a.annotationType();
-                                       if (ca == Query.class) {
+                                       if (ca == Path.class) {
+                                               Path p = (Path)a;
+                                               annotated = pathArgs.add(new 
RemoteMethodArg(p.value(), index, false));
+                                       } else if (ca == Query.class) {
                                                Query q = (Query)a;
                                                annotated = queryArgs.add(new 
RemoteMethodArg(q.value(), index, false));
                                        } else if (ca == QueryIfNE.class) {
@@ -136,6 +141,14 @@ public class RemoteableMethodMeta {
        }
 
        /**
+        * Returns the {@link Path @Path} annotated arguments on this Java 
method.
+        * @return A map of {@link Path#value() @Path.value()} names to 
zero-indexed argument indices.
+        */
+       public RemoteMethodArg[] getPathArgs() {
+               return pathArgs;
+       }
+
+       /**
         * Returns the {@link Query @Query} annotated arguments on this Java 
method.
         * @return A map of {@link Query#value() @Query.value()} names to 
zero-indexed argument indices.
         */

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/3c1ff80f/juneau-core/src/main/javadoc/overview.html
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/javadoc/overview.html 
b/juneau-core/src/main/javadoc/overview.html
index 7a90651..ff4ce10 100644
--- a/juneau-core/src/main/javadoc/overview.html
+++ b/juneau-core/src/main/javadoc/overview.html
@@ -6253,6 +6253,12 @@
 
                <h6 class='topic'>org.apache.juneau.rest.client</h6>
                <ul class='spaced-list'>
+                       <li>New {@link org.apache.juneau.remoteable.Path @Path} 
annotation for specifying path variables on remoteable interfaces.
+                       <li>The following annotations (and related methods on 
RestCall) can now take <code>NameValuePairs</code> and beans as input 
+                               when using <js>"*"</js> as the name.
+                               <br>{@link 
org.apache.juneau.remoteable.FormData @FormData},{@link 
org.apache.juneau.remoteable.FormDataIfNE @FormDataIfNE},
+                               {@link org.apache.juneau.remoteable.Query 
@Query},{@link org.apache.juneau.remoteable.QueryIfNE @QueryIfNE},
+                               {@link org.apache.juneau.remoteable.Header 
@Header},{@link org.apache.juneau.remoteable.HeaderIfNE @HeaderIfNE}, 
                </ul>
 
                <h6 class='topic'>org.apache.juneau.microservice</h6>

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/3c1ff80f/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java 
b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
index 5cdcd84..147b9e4 100644
--- 
a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
+++ 
b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
@@ -172,29 +172,33 @@ public final class RestCall {
         * Adds a query parameter to the URI query.
         *
         * @param name The parameter name.
-        * Can be null/blank if the value is a {@link Map} or {@link String}.
+        *      Can be null/blank/* if the value is a {@link Map}, {@link 
String}, {@link NameValuePairs}, or bean.
         * @param value The parameter value converted to a string using UON 
notation.
-        * Can also be a {@link Map} or {@link String} if the name is 
null/blank.
-        * If a {@link String} and the name is null/blank, then calls {@link 
URIBuilder#setCustomQuery(String)}.
+        *      Can also be {@link Map}, {@link String}, {@link 
NameValuePairs}, or bean if the name is null/blank/*.
+        *      If a {@link String} and the name is null/blank/*, then calls 
{@link URIBuilder#setCustomQuery(String)}.
         * @param skipIfEmpty Don't add the pair if the value is empty.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
        @SuppressWarnings("unchecked")
-       public RestCall query(String name, Object value, boolean skipIfEmpty) {
-               if (! isEmpty(name)) {
+       public RestCall query(String name, Object value, boolean skipIfEmpty) 
throws RestCallException {
+               if (! ("*".equals(name) || isEmpty(name))) {
                        if (! (isEmpty(value) && skipIfEmpty))
                                uriBuilder.addParameter(name, 
client.getUrlEncodingSerializer().serializePart(value, false, null));
+               } else if (value instanceof NameValuePairs) {
+                       for (NameValuePair p : (NameValuePairs)value)
+                               query(p.getName(), p.getValue(), skipIfEmpty);
+               } else if (value instanceof String) {
+                       String s = value.toString();
+                       if (! isEmpty(s))
+                               uriBuilder.setCustomQuery(s);
+               } else if (value instanceof Map) {
+                       for (Map.Entry<String,Object> p : ((Map<String,Object>) 
value).entrySet())
+                               query(p.getKey(), p.getValue(), skipIfEmpty);
+               } else if (isBean(value)){
+                       return query(name, toBeanMap(value));
                } else {
-                       if (value instanceof String) {
-                               String s = value.toString();
-                               if (! isEmpty(s))
-                                       uriBuilder.setCustomQuery(s);
-                       } else if (value instanceof Map) {
-                               for (Map.Entry<String,Object> p : 
((Map<String,Object>) value).entrySet())
-                                       query(p.getKey(), p.getValue(), 
skipIfEmpty);
-                       } else {
-                               throw new RuntimeException("Invalid name passed 
to query(name,value,skipIfEmpty).");
-                       }
+                       throw new RuntimeException("Invalid name passed to 
query(name,value,skipIfEmpty).");
                }
                return this;
        }
@@ -264,28 +268,29 @@ public final class RestCall {
         * Adds a form data pair to this request to perform a URL-encoded form 
post.
         *
         * @param name The parameter name.
-        * Can be null/blank if the value is a {@link Map} or {@link 
NameValuePairs}.
+        *      Can be null/blank/* if the value is a {@link Map}, {@link 
NameValuePairs}, or bean.
         * @param value The parameter value converted to a string using UON 
notation.
-        * Can also be a {@link Map} or {@link NameValuePairs}.
+        *      Can also be {@link Map}, {@link NameValuePairs}, or bean if the 
name is null/blank/*.
         * @param skipIfEmpty Don't add the pair if the value is empty.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
        @SuppressWarnings("unchecked")
-       public RestCall formData(String name, Object value, boolean 
skipIfEmpty) {
+       public RestCall formData(String name, Object value, boolean 
skipIfEmpty) throws RestCallException {
                if (formData == null)
                        formData = new NameValuePairs();
-               if (! isEmpty(name)) {
+               if (! ("*".equals(name) || isEmpty(name))) {
                        if (! (isEmpty(value) && skipIfEmpty))
                                formData.add(new SerializedNameValuePair(name, 
value, client.getUrlEncodingSerializer()));
+               } else if (value instanceof NameValuePairs) {
+                       formData.addAll((NameValuePairs)value);
+               } else if (value instanceof Map) {
+                       for (Map.Entry<String,Object> p : ((Map<String,Object>) 
value).entrySet())
+                               formData(p.getKey(), p.getValue(), skipIfEmpty);
+               } else if (isBean(value)) {
+                       return formData(name, toBeanMap(value));
                } else {
-                       if (value instanceof NameValuePairs) {
-                               formData.addAll((NameValuePairs)value);
-                       } else if (value instanceof Map) {
-                               for (Map.Entry<String,Object> p : 
((Map<String,Object>) value).entrySet())
-                                       formData(p.getKey(), p.getValue(), 
skipIfEmpty);
-                       } else {
-                               throw new RuntimeException("Invalid name passed 
to formData(name,value,skipIfEmpty).");
-                       }
+                       throw new RuntimeException("Invalid name passed to 
formData(name,value,skipIfEmpty).");
                }
                return this;
        }
@@ -354,6 +359,37 @@ public final class RestCall {
        }
 
        /**
+        * Replaces a variable of the form <js>"{name}"</js> in the URL path 
with the specified value.
+        * @param name The path variable name.
+        * @param value The replacement value.
+        *
+        * @return This object (for method chaining).
+        * @throws RestCallException If variable could not be found in path.
+        */
+       @SuppressWarnings("unchecked")
+       public RestCall path(String name, Object value) throws 
RestCallException {
+               String path = uriBuilder.getPath();
+               if (! ("*".equals(name) || isEmpty(name))) {
+                       String var = "{" + name + "}";
+                       if (path.indexOf(var) == -1)
+                               throw new RestCallException("Path variable 
{"+name+"} was not found in path.");
+                       String newPath = path.replace(var, 
client.getUrlEncodingSerializer().serializePart(value, false, null));
+                       uriBuilder.setPath(newPath);
+               } else if (value instanceof NameValuePairs) {
+                       for (NameValuePair p : (NameValuePairs)value)
+                               path(p.getName(), p.getValue());
+               } else if (value instanceof Map) {
+                       for (Map.Entry<String,Object> p : ((Map<String,Object>) 
value).entrySet())
+                               path(p.getKey(), p.getValue());
+               } else if (isBean(value)) {
+                       return path(name, toBeanMap(value));
+               } else {
+                       throw new RuntimeException("Invalid name passed to 
path(name,value).");
+               }
+               return this;
+       }
+
+       /**
         * Sets the URI user info.
         *
         * @param userInfo The new URI user info.
@@ -436,19 +472,23 @@ public final class RestCall {
         * @param value The header value.
         * @param skipIfEmpty Don't add the header if the name is null/empty.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
        @SuppressWarnings("unchecked")
-       public RestCall header(String name, Object value, boolean skipIfEmpty) {
-               if (! isEmpty(name)) {
+       public RestCall header(String name, Object value, boolean skipIfEmpty) 
throws RestCallException {
+               if (! ("*".equals(name) || isEmpty(name))) {
                        if (! (isEmpty(value) && skipIfEmpty))
                                request.setHeader(name, 
client.getUrlEncodingSerializer().serializePart(value, false, true));
+               } else if (value instanceof NameValuePairs) {
+                       for (NameValuePair p : (NameValuePairs)value)
+                               header(p.getName(), p.getValue(), skipIfEmpty);
+               } else if (value instanceof Map) {
+                       for (Map.Entry<String,Object> p : ((Map<String,Object>) 
value).entrySet())
+                               header(p.getKey(), p.getValue(), skipIfEmpty);
+               } else if (isBean(value)) {
+                       return header(name, toBeanMap(value), skipIfEmpty);
                } else {
-                       if (value instanceof Map) {
-                               for (Map.Entry<String,Object> p : 
((Map<String,Object>) value).entrySet())
-                                       header(p.getKey(), p.getValue(), 
skipIfEmpty);
-                       } else {
-                               throw new RuntimeException("Invalid name passed 
to formData(name,value,skipIfEmpty).");
-                       }
+                       throw new RuntimeException("Invalid name passed to 
header(name,value,skipIfEmpty).");
                }
                return this;
        }
@@ -461,8 +501,9 @@ public final class RestCall {
         * The name can be null/empty if the value is a {@link Map}.
         * @param value The header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall header(String name, Object value) {
+       public RestCall header(String name, Object value) throws 
RestCallException {
                return header(name, value, false);
        }
 
@@ -471,8 +512,9 @@ public final class RestCall {
         *
         * @param values The header values.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall headers(Map<String,Object> values) {
+       public RestCall headers(Map<String,Object> values) throws 
RestCallException {
                return header(null, values, false);
        }
 
@@ -485,8 +527,9 @@ public final class RestCall {
         * The name can be null/empty if the value is a {@link Map}.
         * @param value The header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall headerIfNE(String name, Object value) {
+       public RestCall headerIfNE(String name, Object value) throws 
RestCallException {
                return header(name, value, true);
        }
 
@@ -497,8 +540,9 @@ public final class RestCall {
         *
         * @param values The header values.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall headersIfNE(Map<String,Object> values) {
+       public RestCall headersIfNE(Map<String,Object> values) throws 
RestCallException {
                return header(null, values, true);
        }
 
@@ -509,8 +553,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall accept(Object value) {
+       public RestCall accept(Object value) throws RestCallException {
                return header("Accept", value);
        }
 
@@ -521,8 +566,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall acceptCharset(Object value) {
+       public RestCall acceptCharset(Object value) throws RestCallException {
                return header("Accept-Charset", value);
        }
 
@@ -533,8 +579,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall acceptEncoding(Object value) {
+       public RestCall acceptEncoding(Object value) throws RestCallException {
                return header("Accept-Encoding", value);
        }
 
@@ -545,8 +592,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall acceptLanguage(Object value) {
+       public RestCall acceptLanguage(Object value) throws RestCallException {
                return header("Accept-Language", value);
        }
 
@@ -557,8 +605,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall authorization(Object value) {
+       public RestCall authorization(Object value) throws RestCallException {
                return header("Authorization", value);
        }
 
@@ -569,8 +618,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall cacheControl(Object value) {
+       public RestCall cacheControl(Object value) throws RestCallException {
                return header("Cache-Control", value);
        }
 
@@ -581,8 +631,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall connection(Object value) {
+       public RestCall connection(Object value) throws RestCallException {
                return header("Connection", value);
        }
 
@@ -593,8 +644,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall contentLength(Object value) {
+       public RestCall contentLength(Object value) throws RestCallException {
                return header("Content-Length", value);
        }
 
@@ -605,8 +657,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall contentType(Object value) {
+       public RestCall contentType(Object value) throws RestCallException {
                return header("Content-Type", value);
        }
 
@@ -617,8 +670,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall date(Object value) {
+       public RestCall date(Object value) throws RestCallException {
                return header("Date", value);
        }
 
@@ -629,8 +683,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall expect(Object value) {
+       public RestCall expect(Object value) throws RestCallException {
                return header("Expect", value);
        }
 
@@ -641,8 +696,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall forwarded(Object value) {
+       public RestCall forwarded(Object value) throws RestCallException {
                return header("Forwarded", value);
        }
 
@@ -653,8 +709,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall from(Object value) {
+       public RestCall from(Object value) throws RestCallException {
                return header("From", value);
        }
 
@@ -665,8 +722,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall host(Object value) {
+       public RestCall host(Object value) throws RestCallException {
                return header("Host", value);
        }
 
@@ -677,8 +735,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall ifMatch(Object value) {
+       public RestCall ifMatch(Object value) throws RestCallException {
                return header("If-Match", value);
        }
 
@@ -689,8 +748,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall ifModifiedSince(Object value) {
+       public RestCall ifModifiedSince(Object value) throws RestCallException {
                return header("If-Modified-Since", value);
        }
 
@@ -701,8 +761,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall ifNoneMatch(Object value) {
+       public RestCall ifNoneMatch(Object value) throws RestCallException {
                return header("If-None-Match", value);
        }
 
@@ -713,8 +774,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall ifRange(Object value) {
+       public RestCall ifRange(Object value) throws RestCallException {
                return header("If-Range", value);
        }
 
@@ -725,8 +787,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall ifUnmodifiedSince(Object value) {
+       public RestCall ifUnmodifiedSince(Object value) throws 
RestCallException {
                return header("If-Unmodified-Since", value);
        }
 
@@ -737,8 +800,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall maxForwards(Object value) {
+       public RestCall maxForwards(Object value) throws RestCallException {
                return header("Max-Forwards", value);
        }
 
@@ -749,8 +813,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall origin(Object value) {
+       public RestCall origin(Object value) throws RestCallException {
                return header("Origin", value);
        }
 
@@ -761,8 +826,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall pragma(Object value) {
+       public RestCall pragma(Object value) throws RestCallException {
                return header("Pragma", value);
        }
 
@@ -773,8 +839,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall proxyAuthorization(Object value) {
+       public RestCall proxyAuthorization(Object value) throws 
RestCallException {
                return header("Proxy-Authorization", value);
        }
 
@@ -785,8 +852,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall range(Object value) {
+       public RestCall range(Object value) throws RestCallException {
                return header("Range", value);
        }
 
@@ -797,8 +865,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall referer(Object value) {
+       public RestCall referer(Object value) throws RestCallException {
                return header("Referer", value);
        }
 
@@ -809,8 +878,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall te(Object value) {
+       public RestCall te(Object value) throws RestCallException {
                return header("TE", value);
        }
 
@@ -821,8 +891,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall userAgent(Object value) {
+       public RestCall userAgent(Object value) throws RestCallException {
                return header("User-Agent", value);
        }
 
@@ -833,8 +904,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall upgrade(Object value) {
+       public RestCall upgrade(Object value) throws RestCallException {
                return header("Upgrade", value);
        }
 
@@ -845,8 +917,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall via(Object value) {
+       public RestCall via(Object value) throws RestCallException {
                return header("Via", value);
        }
 
@@ -857,8 +930,9 @@ public final class RestCall {
         *
         * @param value The new header value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall warning(Object value) {
+       public RestCall warning(Object value) throws RestCallException {
                return header("Warning", value);
        }
 
@@ -867,8 +941,9 @@ public final class RestCall {
         *
         * @param version The version string (e.g. <js>"1.2.3"</js>)
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall clientVersion(String version) {
+       public RestCall clientVersion(String version) throws RestCallException {
                return header("X-Client-Version", version);
        }
 
@@ -1827,9 +1902,18 @@ public final class RestCall {
         *
         * @param value The debug value.
         * @return This object (for method chaining).
+        * @throws RestCallException
         */
-       public RestCall debug(boolean value) {
+       public RestCall debug(boolean value) throws RestCallException {
                header("Debug", value);
                return this;
        }
+
+       private boolean isBean(Object o) throws RestCallException {
+               return getBeanContext().isBean(o);
+       }
+
+       private BeanMap<?> toBeanMap(Object o) throws RestCallException {
+               return getBeanContext().createSession().toBeanMap(o);
+       }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/3c1ff80f/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
 
b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
index e5f9a32..b026ff4 100644
--- 
a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
+++ 
b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
@@ -537,6 +537,9 @@ public class RestClient extends CoreObject {
                                                        RestCall rc = 
(httpMethod.equals("POST") ? doPost(url) : doGet(url));
                                                        
rc.serializer(serializer).parser(parser);
 
+                                                       for (RemoteMethodArg a 
: rmm.getPathArgs())
+                                                               rc.path(a.name, 
args[a.index]);
+
                                                        for (RemoteMethodArg a 
: rmm.getQueryArgs())
                                                                
rc.query(a.name, args[a.index], a.skipIfNE);
 
@@ -598,6 +601,8 @@ public class RestClient extends CoreObject {
                                s = sb.toString();
                        }
                }
+               if (s.indexOf('{') != -1)
+                       s = s.replace("{", "%7B").replace("}", "%7D");
                return new URI(s);
        }
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/3c1ff80f/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ThirdPartyProxyResource.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ThirdPartyProxyResource.java
 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ThirdPartyProxyResource.java
index 1d583ce..d039d30 100644
--- 
a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ThirdPartyProxyResource.java
+++ 
b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ThirdPartyProxyResource.java
@@ -447,6 +447,55 @@ public class ThirdPartyProxyResource extends ResourceJena {
                return "OK";
        }
 
+       @RestMethod(name="GET", path="/stringQuery1")
+       public String stringQuery1(
+                       @Query("a") int a,
+                       @Query("b") String b
+               ) throws Exception {
+
+               assertEquals(1, a);
+               assertEquals("foo", b);
+
+               return "OK";
+       }
+
+       @RestMethod(name="GET", path="/stringQuery2")
+       public String stringQuery2(
+                       @Query("a") int a,
+                       @Query("b") String b
+               ) throws Exception {
+
+               assertEquals(1, a);
+               assertEquals("foo", b);
+
+               return "OK";
+       }
+
+       @RestMethod(name="GET", path="/mapQuery")
+       public String mapQuery(
+                       @Query("a") int a,
+                       @Query("b") String b
+               ) throws Exception {
+
+               assertEquals(1, a);
+               assertEquals("foo", b);
+
+               return "OK";
+       }
+
+       @RestMethod(name="GET", path="/beanQuery")
+       public String beanQuery(
+                       @Query("a") int a,
+                       @Query("b") String b
+               ) throws Exception {
+
+               assertEquals(1, a);
+               assertEquals("foo", b);
+
+               return "OK";
+       }
+
+
        
//--------------------------------------------------------------------------------
        // FormData tests
        
//--------------------------------------------------------------------------------
@@ -654,6 +703,49 @@ public class ThirdPartyProxyResource extends ResourceJena {
                return "OK";
        }
 
+
+       
//--------------------------------------------------------------------------------
+       // Path tests
+       
//--------------------------------------------------------------------------------
+
+       @RestMethod(name="POST", path="/pathVars1/{a}/{b}")
+       public String pathVars1(
+               @Path("a") int a,
+               @Path("b") String b
+               ) throws Exception {
+
+               assertEquals(1, a);
+               assertEquals("foo", b);
+
+               return "OK";
+       }
+
+
+       @RestMethod(name="POST", path="/pathVars2/{a}/{b}")
+       public String pathVars2(
+               @Path("a") int a,
+               @Path("b") String b
+               ) throws Exception {
+
+               assertEquals(1, a);
+               assertEquals("foo", b);
+
+               return "OK";
+       }
+
+       @RestMethod(name="POST", path="/pathVars3/{a}/{b}")
+       public String pathVars3(
+               @Path("a") int a,
+               @Path("b") String b
+               ) throws Exception {
+
+               assertEquals(1, a);
+               assertEquals("foo", b);
+
+               return "OK";
+       }
+
+
        
//--------------------------------------------------------------------------------
        // Test return types.
        
//--------------------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/3c1ff80f/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/ThirdPartyProxyTest.java
----------------------------------------------------------------------
diff --git 
a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/ThirdPartyProxyTest.java
 
b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/ThirdPartyProxyTest.java
index 2f69bb1..7b73358 100644
--- 
a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/ThirdPartyProxyTest.java
+++ 
b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/ThirdPartyProxyTest.java
@@ -300,6 +300,34 @@ public class ThirdPartyProxyTest extends RestTestcase {
                assertEquals("OK", r);
        }
 
+       @Test
+       public void b08_stringQuery1() throws Exception {
+               String r = proxy.stringQuery1("a=1&b=foo");
+               assertEquals("OK", r);
+       }
+
+       @Test
+       public void b09_stringQuery2() throws Exception {
+               String r = proxy.stringQuery2("a=1&b=foo");
+               assertEquals("OK", r);
+       }
+
+       @Test
+       public void b10_mapQuery() throws Exception {
+               String r = proxy.mapQuery(
+                       new AMap<String,Object>().append("a", 1).append("b", 
"foo")
+               );
+               assertEquals("OK", r);
+       }
+
+       @Test
+       public void b11_beanQuery() throws Exception {
+               String r = proxy.beanQuery(
+                       new ABean().init()
+               );
+               assertEquals("OK", r);
+       }
+
        
//--------------------------------------------------------------------------------
        // FormData tests
        
//--------------------------------------------------------------------------------
@@ -1050,6 +1078,30 @@ public class ThirdPartyProxyTest extends RestTestcase {
                proxy.setEnum1d3dListMap(new 
AMap<TestEnum,List<TestEnum[][][]>>().append(TestEnum.ONE, new 
AList<TestEnum[][][]>().append(new 
TestEnum[][][]{{{TestEnum.TWO,null},null},null}).append(null)));
        }
 
+       // Path variables
+
+       @Test
+       public void f01_pathVars1() {
+               String r = proxy.pathVars1(1, "foo");
+               assertEquals("OK", r);
+       }
+
+       @Test
+       public void f02_pathVars2() {
+               String r = proxy.pathVars2(
+                       new AMap<String,Object>().append("a", 1).append("b", 
"foo")
+               );
+               assertEquals("OK", r);
+       }
+
+       @Test
+       public void f03_pathVars3() {
+               String r = proxy.pathVars3(
+                       new ABean().init()
+               );
+               assertEquals("OK", r);
+       }
+
 
        
//--------------------------------------------------------------------------------
        // Proxy class
@@ -1224,6 +1276,27 @@ public class ThirdPartyProxyTest extends RestTestcase {
                        @Query("h8") Map<TestEnum,List<TestEnum[][][]>> h8
                );
 
+               @RemoteMethod(httpMethod="GET", path="/stringQuery1")
+               String stringQuery1(
+                       @Query() String q
+               );
+
+               @RemoteMethod(httpMethod="GET", path="/stringQuery2")
+               String stringQuery2(
+                       @Query("*") String q
+               );
+
+               @RemoteMethod(httpMethod="GET", path="/mapQuery")
+               String mapQuery(
+                       @Query("*") Map<String,Object> q
+               );
+
+               @RemoteMethod(httpMethod="GET", path="/beanQuery")
+               String beanQuery(
+                       @Query("*") ABean q
+               );
+
+
                
//--------------------------------------------------------------------------------
                // FormData tests
                
//--------------------------------------------------------------------------------
@@ -1308,6 +1381,26 @@ public class ThirdPartyProxyTest extends RestTestcase {
                );
 
                
//--------------------------------------------------------------------------------
+               // Path tests
+               
//--------------------------------------------------------------------------------
+
+               @RemoteMethod(httpMethod="POST", path="/pathVars1/{a}/{b}")
+               String pathVars1(
+                       @Path("a") int a,
+                       @Path("b") String b
+               );
+
+               @RemoteMethod(httpMethod="POST", path="/pathVars2/{a}/{b}")
+               String pathVars2(
+                       @Path Map<String,Object> p
+               );
+
+               @RemoteMethod(httpMethod="POST", path="/pathVars3/{a}/{b}")
+               String pathVars3(
+                       @Path ABean p
+               );
+
+               
//--------------------------------------------------------------------------------
                // Test return types.
                
//--------------------------------------------------------------------------------
 


Reply via email to