You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2018/07/18 23:35:23 UTC

[juneau] branch master updated: Remove @PathRemainder annotation.

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 a82ab9f  Remove @PathRemainder annotation.
a82ab9f is described below

commit a82ab9fd8e6a5bc8a98e20669173db5ece4c38b2
Author: JamesBognar <ja...@apache.org>
AuthorDate: Wed Jul 18 19:35:06 2018 -0400

    Remove @PathRemainder annotation.
---
 .../apache/juneau/http/annotation/FormData.java    |  7 +++
 .../org/apache/juneau/http/annotation/Header.java  |  7 +++
 .../org/apache/juneau/http/annotation/Path.java    | 13 ++++-
 .../juneau/http/annotation/PathRemainder.java      | 59 ----------------------
 .../org/apache/juneau/http/annotation/Query.java   |  7 +++
 .../juneau/httppart/HttpPartSchemaBuilder.java     |  5 ++
 juneau-doc/src/main/javadoc/overview.html          | 17 ++++---
 .../examples/rest/MethodExampleResource.java       |  2 +-
 .../rest/addressbook/AddressBookResource.java      |  4 +-
 .../microservice/resources/DirectoryResource.java  | 10 ++--
 .../microservice/resources/LogsResource.java       | 10 ++--
 .../rest/test/client/RequestBeanProxyTest.java     |  4 +-
 .../org/apache/juneau/rest/client/RestCall.java    |  9 +++-
 .../org/apache/juneau/rest/RequestPathMatch.java   | 15 ++++--
 .../java/org/apache/juneau/rest/RestContext.java   |  3 --
 .../org/apache/juneau/rest/RestParamDefaults.java  | 12 -----
 .../java/org/apache/juneau/rest/RestRequest.java   |  2 +-
 .../java/org/apache/juneau/rest/PathsTest.java     |  8 +--
 .../juneau/rest/annotation/PathAnnotationTest.java |  2 +-
 .../annotation/PathRemainderAnnotationTest.java    |  2 +-
 20 files changed, 87 insertions(+), 111 deletions(-)

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/FormData.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/FormData.java
index e6e0efb..d660377 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/FormData.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/FormData.java
@@ -62,6 +62,13 @@ import org.apache.juneau.urlencoding.*;
  * 	}
  * </p>
  *
+ * <p>
+ * Any of the following types can be used for the parameter or POJO class:
+ * <ol class='spaced-list'>
+ * 	<li>
+ * 		Objects convertible from data types inferred from Swagger schema annotations using the registered {@link OpenApiPartParser}.
+ * </ol>
+ *
  * <h5 class='topic'>Important note concerning FORM posts</h5>
  *
  * This annotation should not be combined with the {@link Body @Body} annotation or <code>RestRequest.getBody()</code> method
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Header.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Header.java
index 1a6621b..77ac326 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Header.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Header.java
@@ -59,6 +59,13 @@ import org.apache.juneau.urlencoding.*;
  * 	}
  * </p>
  *
+ * <p>
+ * Any of the following types can be used for the parameter or POJO class:
+ * <ol class='spaced-list'>
+ * 	<li>
+ * 		Objects convertible from data types inferred from Swagger schema annotations using the registered {@link OpenApiPartParser}.
+ * </ol>
+ *
  * <h5 class='section'>See Also:</h5>
  * <ul>
  * 	<li class='link'><a class="doclink" href="../../../../../overview-summary.html#juneau-rest-server.Header">Overview &gt; juneau-rest-server &gt; @Header</a>
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Path.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Path.java
index 6f1d99b..0f5c020 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Path.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Path.java
@@ -26,7 +26,7 @@ import org.apache.juneau.urlencoding.*;
   * REST request path annotation.
  *
  * <p>
- * Identifies a POJO to be used as a patn entry on an HTTP request.
+ * Identifies a POJO to be used as a path entry on an HTTP request.
  *
  * <p>
  * Can be used in the following locations:
@@ -49,6 +49,13 @@ import org.apache.juneau.urlencoding.*;
  * 	}
  * </p>
  *
+ * <p>
+ * Any of the following types can be used for the parameter or POJO class:
+ * <ol class='spaced-list'>
+ * 	<li>
+ * 		Objects convertible from data types inferred from Swagger schema annotations using the registered {@link OpenApiPartParser}.
+ * </ol>
+ *
  * <h5 class='section'>See Also:</h5>
  * <ul>
  * 	<li class='link'><a class="doclink" href="../../../../../overview-summary.html#juneau-rest-server.Path">Overview &gt; juneau-rest-server &gt; @Path</a>
@@ -244,6 +251,10 @@ public @interface Path {
 	 * URL path variable name.
 	 *
 	 * <p>
+	 * The path remainder after the path match can be referenced using the name <js>"/*"</js>.
+	 * <br>The non-URL-decoded path remainder after the path match can be referenced using the name <js>"/**"</js>.
+	 *
+	 * <p>
 	 * The name field MUST correspond to the associated <a href='https://swagger.io/specification/v2/#pathsPath'>path</a> segment from the path field in the <a href='https://swagger.io/specification/v2/#pathsObject'>Paths Object</a>.
 	 * See <a href='https://swagger.io/specification/v2/#pathTemplating'>Path Templating</a> for further information.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/PathRemainder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/PathRemainder.java
deleted file mode 100644
index e7fcd90..0000000
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/PathRemainder.java
+++ /dev/null
@@ -1,59 +0,0 @@
-// ***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                                                              *
-// *                                                                                                                         *
-// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
-// *                                                                                                                         *
-// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the License.                                              *
-// ***************************************************************************************************************************
-package org.apache.juneau.http.annotation;
-
-import static java.lang.annotation.ElementType.*;
-import static java.lang.annotation.RetentionPolicy.*;
-
-import java.lang.annotation.*;
-
-/**
- * REST request path remainder annotation.
- *
- * <p>
- * Identifies a parameter as the URL path remainder after a path pattern match.
- *
- * <p>
- * Can be used in the following locations:
- * <ul>
- * 	<li>Java method arguments and argument-types of server-side <ja>@RestMethod</ja>-annotated REST Java methods.
- * </ul>
- *
- * <h5 class='section'>Example:</h5>
- * <p class='bcode'>
- * 	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foo/*"</js>)
- * 	<jk>public void</jk> doGet(RestRequest req, RestResponse res, <ja>@PathRemainder</ja> String remainder) {
- * 		...
- * 	}
- * </p>
- *
- * <p>
- * This is functionally equivalent to the following code...
- * <p class='bcode'>
- * 	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foo/*"</js>)
- * 	<jk>public void</jk> doGet(RestRequest req, RestResponse res) {
- * 		String remainder = req.getPathRemainder();
- * 		...
- * 	}
- * </p>
- *
- * <h5 class='section'>See Also:</h5>
- * <ul>
- * 	<li class='link'><a class="doclink" href="../../../../../overview-summary.html#juneau-rest-server.PathRemainder">Overview &gt; juneau-rest-server &gt; @PathRemainder</a>
- * </ul>
- */
-@Documented
-@Target(PARAMETER)
-@Retention(RUNTIME)
-@Inherited
-public @interface PathRemainder {}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Query.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Query.java
index cb14db2..72bf11b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Query.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Query.java
@@ -68,6 +68,13 @@ import org.apache.juneau.urlencoding.*;
  * 	}
  * </p>
  *
+ * <p>
+ * Any of the following types can be used for the parameter or POJO class:
+ * <ol class='spaced-list'>
+ * 	<li>
+ * 		Objects convertible from data types inferred from Swagger schema annotations using the registered {@link OpenApiPartParser}.
+ * </ol>
+ *
  * <h5 class='section'>See Also:</h5>
  * <ul>
  * 	<li class='link'><a class="doclink" href="../../../../../overview-summary.html#juneau-rest-server.Query">Overview &gt; juneau-rest-server &gt; @Query</a>
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java
index f7b7388..83eac7c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java
@@ -266,6 +266,11 @@ public class HttpPartSchemaBuilder {
 		multipleOf(HttpPartSchema.toNumber(a.multipleOf()));
 		parser(a.parser());
 		serializer(a.serializer());
+
+		// Path remainder always allows empty value.
+		if (startsWith(name, '/'))
+			allowEmptyValue();
+
 		return this;
 	}
 
diff --git a/juneau-doc/src/main/javadoc/overview.html b/juneau-doc/src/main/javadoc/overview.html
index 5403156..d2d519f 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -309,7 +309,6 @@
 		<li><p><a class='doclink' href='#juneau-rest-server.HasQuery'>@HasQuery</a></p>
 		<li><p><a class='doclink' href='#juneau-rest-server.Header'>@Header</a></p>
 		<li><p><a class='doclink' href='#juneau-rest-server.Path'>@Path</a></p>
-		<li><p><a class='doclink' href='#juneau-rest-server.PathRemainder'>@PathRemainder</a></p>
 		<li><p><a class='doclink' href='#juneau-rest-server.SwaggerSchemaPartParsing'>Swagger Schema Part Parsing</a></p>
 		<li><p><a class='doclink' href='#juneau-rest-server.Response'>@Response</a></p>
 		<li><p><a class='doclink' href='#juneau-rest-server.Responses'>@Responses</a></p>
@@ -12053,7 +12052,7 @@
 		<ja>@Query</ja>(<js>"p2"</js>) String p2,
 		<ja>@Query</ja>(<js>"p3"</js>) UUID p3,
 		<ja>@HasQuery</ja>(<js>"p3"</js>) boolean hasP3,
-		<ja>@PathRemainder</ja> String remainder,
+		<ja>@Path</ja>(<js>"/*"</js>) String remainder,
 		<ja>@Header</ja>(<js>"Accept-Language"</js>) String lang,
 		<ja>@Header</ja>(<js>"Accept"</js>) String accept,
 		<ja>@Header</ja>(<js>"DNT"</js>) <jk>int</jk> doNotTrack,
@@ -12400,7 +12399,7 @@
 				Paths that end with <js>"/*"</js> will do a prefix match on the incoming URL.  
 				<br>Any remainder after the match can be accessed through 
 				{@link org.apache.juneau.rest.RequestPathMatch#getRemainder()} or parameters with the 
-				{@link org.apache.juneau.http.annotation.PathRemainder @PathRemainder} annotation.
+				<code><ja>@Path</ja>(<js>"/*"</js>)</code> annotation.
 				<br>On the other hand, paths that don't end with <js>"/*"</js> (e.g. <js>"/"</js> or <js>"/foo"</js>) will 
 				require an exact URL match, and if any remainder exists, a 404 (not found) error will be thrown.
 			</p>
@@ -12409,7 +12408,7 @@
 			</p>
 			<p class='bcode w800'>
 	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/*"</js>)
-	<jk>public void</jk> doGet(<ja>@PathRemainder</ja> String remainder) {
+	<jk>public void</jk> doGet(<ja>@Path</ja>(<js>"/*"</js>) String remainder) {
 		<jc>// URL path pattern can have remainder accessible through req.getRemainder().</jc>
 	}
 
@@ -19477,7 +19476,7 @@
 				<ja>@Query</ja>(<js>"q1"</js>) <jk>int</jk> q1,                    <jc>// Query parameters.</jc>
 				<ja>@Query</ja>(<js>"q2"</js>) String q2,
 				<ja>@Query</ja>(<js>"q3"</js>) UUID q3,
-				<ja>@PathRemainder</ja> String remainder,        <jc>// Path remainder after pattern match.</jc>
+				<ja>@Path</ja>(<js>"/*"</js>) String remainder,        <jc>// Path remainder after pattern match.</jc>
 				<ja>@Header</ja>(<js>"Accept-Language"</js>) String lang, <jc>// Headers.</jc>
 				<ja>@Header</ja>(<js>"Accept"</js>) String accept,
 				<ja>@Header</ja>(<js>"DNT"</js>) <jk>int</jk> doNotTrack
@@ -19611,7 +19610,6 @@
 					<li class='ja'>{@link org.apache.juneau.http.annotation.Query @Query}
 					<li class='ja'>{@link org.apache.juneau.http.annotation.Header @Header}
 					<li class='ja'>{@link org.apache.juneau.rest.annotation.Method @Method}
-					<li class='ja'>{@link org.apache.juneau.http.annotation.PathRemainder @PathRemainder}
 				</ul>
 				Method returns a POJO to be serialized as the output.
 			<li class='jm'>
@@ -20626,7 +20624,7 @@
 		<ja>@RestMethod</ja>(name=<jsf>PUT</jsf>, path=<js>"/people/{id}/*"</js>, 
 			guards=AdminGuard.<jk>class</jk> 
 		) 
-		<jk>public</jk> String updatePerson(RestRequest req, <ja>@Path</ja>(<js>"id"</js>) <jk>int</jk> id, <ja>@PathRemainder</ja> 
+		<jk>public</jk> String updatePerson(RestRequest req, <ja>@Path</ja>(<js>"id"</js>) <jk>int</jk> id, <ja>@Path</ja>(<js>"/*"</js>) 
 				String remainder) <jk>throws</jk> Exception { 
 			<jk>try</jk> { 
 				Person p = findPerson(id); 
@@ -20648,7 +20646,7 @@
 			guards=AdminGuard.<jk>class</jk> 
 		) 
 		<jk>public</jk> String updateAddress(RestRequest req, <ja>@Path</ja>(<js>"id"</js>) <jk>int</jk> id, 
-				<ja>@PathRemainder</ja> String remainder) <jk>throws</jk> Exception { 
+				<ja>@Path</ja>(<js>"/*"</js>) String remainder) <jk>throws</jk> Exception { 
 			<jk>try</jk> { 
 				Address a = findAddress(id); 
 				PojoRest r = <jk>new</jk> PojoRest(a); 
@@ -22897,6 +22895,9 @@
 					<li class='ja'>{@link org.apache.juneau.http.annotation.Query}
 				</ul>
 			<li>
+				The <ja>@PathRemainder</ja> annotation has been removed entirely.  
+				<br>Use <code><ja>@Path</ja>(<js>"/*"</js>)</code> to access the path remainder which includes all the new OpenAPI parsing support.
+			<li>
 				"Helper" classes (i.e. reusable beans that can be returned by REST methods) have been moved to the following package with some new additions:
 				<ul class='doctree'>
 					<li class='jp'>{@link org.apache.juneau.rest.helper}
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/MethodExampleResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/MethodExampleResource.java
index e647516..f9a29fb 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/MethodExampleResource.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/MethodExampleResource.java
@@ -88,7 +88,7 @@ public class MethodExampleResource extends BasicRestServlet {
 			@Query("q1") int q1,                    // Query parameters.
 			@Query("q2") String q2,
 			@Query(name="q3",_default=SAMPLE_UUID_STRING) UUID q3,
-			@PathRemainder String remainder,        // Path remainder after pattern match.
+			@Path("/*") String remainder,        // Path remainder after pattern match.
 			@Header("Accept-Language") String lang, // Headers.
 			@Header("Accept") String accept,
 			@Header(name="DNT",_default="1") Integer doNotTrack
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java
index cb0548e..4f36691 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java
@@ -278,7 +278,7 @@ public class AddressBookResource extends BasicRestServletJena {
 	@RestMethod(name=PUT, path="/people/{id}/*",
 		guards=AdminGuard.class
 	)
-	public String updatePerson(RequestBody body, @Path("id") int id, @PathRemainder String remainder) throws BadRequest {
+	public String updatePerson(RequestBody body, @Path("id") int id, @Path("/*") String remainder) throws BadRequest {
 		try {
 			Person p = findPerson(id);
 			PojoRest r = new PojoRest(p);
@@ -298,7 +298,7 @@ public class AddressBookResource extends BasicRestServletJena {
 	@RestMethod(name=PUT, path="/addresses/{id}/*",
 		guards=AdminGuard.class
 	)
-	public String updateAddress(RestRequest req, @Path("id") int id, @PathRemainder String remainder) throws BadRequest {
+	public String updateAddress(RestRequest req, @Path("id") int id, @Path("/*") String remainder) throws BadRequest {
 		try {
 			Address a = findAddress(id);
 			PojoRest r = new PojoRest(a);
diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java
index 7659cec..6a1095f 100755
--- a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java
+++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java
@@ -126,7 +126,7 @@ public class DirectoryResource extends BasicRestServlet {
 			nav={"<h5>Folder:  $RA{fullPath}</h5>"}
 		)
 	)
-	public FileResource getFile(RestRequest req, @PathRemainder String path) throws NotFound, Exception {
+	public FileResource getFile(RestRequest req, @Path("/*") String path) throws NotFound, Exception {
 
 		File dir = getFile(path);
 		req.setAttribute("fullPath", dir.getAbsolutePath());
@@ -140,7 +140,7 @@ public class DirectoryResource extends BasicRestServlet {
 		summary="View contents of file",
 		description="View the contents of a file.\nContent-Type is set to 'text/plain'."
 	)
-	public FileContents viewFile(RestResponse res, @PathRemainder String path) throws NotFound, MethodNotAllowed {
+	public FileContents viewFile(RestResponse res, @Path("/*") String path) throws NotFound, MethodNotAllowed {
 		if (! allowViews)
 			throw new MethodNotAllowed("VIEW not enabled");
 
@@ -158,7 +158,7 @@ public class DirectoryResource extends BasicRestServlet {
 		summary="Download file",
 		description="Download the contents of a file.\nContent-Type is set to 'application/octet-stream'."
 	)
-	public FileContents downloadFile(RestResponse res, @PathRemainder String path) throws NotFound, MethodNotAllowed {
+	public FileContents downloadFile(RestResponse res, @Path("/*") String path) throws NotFound, MethodNotAllowed {
 		if (! allowViews)
 			throw new MethodNotAllowed("DOWNLOAD not enabled");
 
@@ -176,7 +176,7 @@ public class DirectoryResource extends BasicRestServlet {
 		summary="Delete file",
 		description="Delete a file on the file system."
 	)
-	public RedirectToRoot deleteFile(@PathRemainder String path) throws MethodNotAllowed {
+	public RedirectToRoot deleteFile(@Path("/*") String path) throws MethodNotAllowed {
 		deleteFile(getFile(path));
 		return new RedirectToRoot();
 	}
@@ -189,7 +189,7 @@ public class DirectoryResource extends BasicRestServlet {
 	)
 	public RedirectToRoot updateFile(
 		@Body(schema=@Schema(type="string",format="binary")) InputStream is,
-		@PathRemainder String path
+		@Path("/*") String path
 	) throws InternalServerError {
 
 		if (! allowUploads)
diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java
index 47a190c..595936b 100755
--- a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java
+++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java
@@ -118,7 +118,7 @@ public class LogsResource extends BasicRestServlet {
 			nav={"<h5>Folder:  $RA{fullPath}</h5>"}
 		)
 	)
-	public FileResource getFile(RestRequest req, @PathRemainder String path) throws NotFound, Exception {
+	public FileResource getFile(RestRequest req, @Path("/*") String path) throws NotFound, Exception {
 
 		File dir = getFile(path);
 		req.setAttribute("fullPath", dir.getAbsolutePath());
@@ -134,7 +134,7 @@ public class LogsResource extends BasicRestServlet {
 	)
 	public void viewFile(
 			RestResponse res,
-			@PathRemainder String path,
+			@Path("/*") String path,
 			@Query(name="highlight", description="Add severity color highlighting.", example="true") boolean highlight,
 			@Query(name="start", description="Start timestamp (ISO8601, full or partial).\nDon't print lines logged before the specified timestamp.\nUse any of the following formats: yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddThh, yyyy-MM-ddThh:mm, yyyy-MM-ddThh:mm:ss, yyyy-MM-ddThh:mm:ss.SSS", example="2014-01-23T11:25:47") String start,
 			@Query(name="end", description="End timestamp (ISO8601, full or partial).\nDon't print lines logged after the specified timestamp.\nUse any of the following formats: yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddThh, yyyy-MM-ddThh:mm, yyyy-MM-ddThh:mm:ss, yyyy-MM-ddThh:mm:ss.SSS", example="2014-01-24") String end,
@@ -203,7 +203,7 @@ public class LogsResource extends BasicRestServlet {
 	)
 	public LogParser viewParsedEntries(
 			RestRequest req,
-			@PathRemainder String path,
+			@Path("/*") String path,
 			@Query(name="start", description="Start timestamp (ISO8601, full or partial).\nDon't print lines logged before the specified timestamp.\nUse any of the following formats: yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddThh, yyyy-MM-ddThh:mm, yyyy-MM-ddThh:mm:ss, yyyy-MM-ddThh:mm:ss.SSS", example="2014-01-23T11:25:47") String start,
 			@Query(name="end", description="End timestamp (ISO8601, full or partial).\nDon't print lines logged after the specified timestamp.\nUse any of the following formats: yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddThh, yyyy-MM-ddThh:mm, yyyy-MM-ddThh:mm:ss, yyyy-MM-ddThh:mm:ss.SSS", example="2014-01-24") String end,
 			@Query(name="thread", description="Thread name filter.\nOnly show log entries with the specified thread name.", example="thread-pool-33-thread-1") String thread,
@@ -225,7 +225,7 @@ public class LogsResource extends BasicRestServlet {
 		summary="Download file",
 		description="Download the contents of a file.\nContent-Type is set to 'application/octet-stream'."
 	)
-	public FileContents downloadFile(RestResponse res, @PathRemainder String path) throws NotFound, MethodNotAllowed {
+	public FileContents downloadFile(RestResponse res, @Path("/*") String path) throws NotFound, MethodNotAllowed {
 		res.setContentType("application/octet-stream");
 		try {
 			return new FileContents(getFile(path));
@@ -240,7 +240,7 @@ public class LogsResource extends BasicRestServlet {
 		summary="Delete log file",
 		description="Delete a log file on the file system."
 	)
-	public RedirectToRoot deleteFile(@PathRemainder String path) throws MethodNotAllowed {
+	public RedirectToRoot deleteFile(@Path("/*") String path) throws MethodNotAllowed {
 		deleteFile(getFile(path));
 		return new RedirectToRoot();
 	}
diff --git a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/RequestBeanProxyTest.java b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/RequestBeanProxyTest.java
index 7d5f064..79dc2f6 100644
--- a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/RequestBeanProxyTest.java
+++ b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/RequestBeanProxyTest.java
@@ -1048,7 +1048,7 @@ public class RequestBeanProxyTest {
 		public NameValuePairs getA() {
 			return new NameValuePairs().append("a1","v1").append("a2", 123).append("a3", null).append("a4", "");
 		}
-		@Path("*")
+		@Path("/*")
 		public NameValuePairs getB() {
 			return new NameValuePairs().append("b1","true").append("b2", "123").append("b3", "null");
 		}
@@ -1056,7 +1056,7 @@ public class RequestBeanProxyTest {
 		public NameValuePairs getC() {
 			return new NameValuePairs().append("c1","v1").append("c2", 123).append("c3", null).append("c4", "");
 		}
-		@Path("*")
+		@Path("/*")
 		public NameValuePairs getD() {
 			return null;
 		}
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
index b3ddec2..9e73861 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
@@ -449,10 +449,15 @@ public final class RestCall extends BeanSession implements Closeable {
 		boolean isMulti = isEmpty(name) || "*".equals(name) || value instanceof NameValuePairs;
 		if (! isMulti) {
 			String var = "{" + name + "}";
-			if (path.indexOf(var) == -1)
+			if (path.indexOf(var) == -1 && ! name.equals("/*"))
 				throw new RestCallException("Path variable {"+name+"} was not found in path.");
 			try {
-				uriBuilder.setPath(path.replace(var, serializer.createSession(null).serialize(HttpPartType.PATH, schema, value)));
+				String p = null;
+				if (name.equals("/*"))
+					p = path.replaceAll("\\/\\*$", serializer.createSession(null).serialize(HttpPartType.PATH, schema, value));
+				else
+					p = path.replace(var, serializer.createSession(null).serialize(HttpPartType.PATH, schema, value));
+				uriBuilder.setPath(p);
 			} catch (SchemaValidationException e) {
 				throw new RestCallException(e, "Validation error on request path parameter ''{0}''=''{1}''", name, value);
 			} catch (SerializeException e) {
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestPathMatch.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestPathMatch.java
index 5b05045..6d3befc 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestPathMatch.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestPathMatch.java
@@ -38,7 +38,7 @@ public class RequestPathMatch extends TreeMap<String,String> {
 
 	private final RestRequest req;
 	private HttpPartParser parser;
-	private String remainder, pattern;
+	private String pattern;
 
 	RequestPathMatch(RestRequest req) {
 		super(String.CASE_INSENSITIVE_ORDER);
@@ -51,7 +51,8 @@ public class RequestPathMatch extends TreeMap<String,String> {
 	}
 
 	RequestPathMatch remainder(String remainder) {
-		this.remainder = remainder;
+		put("/**", remainder);
+		put("/*", urlDecode(remainder));
 		return this;
 	}
 
@@ -317,19 +318,25 @@ public class RequestPathMatch extends TreeMap<String,String> {
 	 * 	}
 	 * </p>
 	 *
+	 * <p>
+	 * The remainder can also be retrieved by calling <code>get(<js>"/*"</js>)</code>.
+	 *
 	 * @return The path remainder string.
 	 */
 	public String getRemainder() {
-		return urlDecode(remainder);
+		return get("/*");
 	}
 
 	/**
 	 * Same as {@link #getRemainder()} but doesn't decode characters.
 	 *
+	 * <p>
+	 * The undecoded remainder can also be retrieved by calling <code>get(<js>"/**"</js>)</code>.
+	 *
 	 * @return The un-decoded path remainder.
 	 */
 	public String getRemainderUndecoded() {
-		return remainder;
+		return get("/**");
 	}
 
 	/**
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index 857a332..d5729ae 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -4379,9 +4379,6 @@ public final class RestContext extends BeanContext {
 				s = HttpPartSchema.create(HasQuery.class, method, i);
 				rp[i] = new RestParamDefaults.HasQueryObject(method, s, t);
 
-			} else if (hasAnnotation(PathRemainder.class, method, i)) {
-				rp[i] = new RestParamDefaults.PathRemainderObject(method, t);
-
 			} else if (hasAnnotation(org.apache.juneau.rest.annotation.Method.class, method, i)) {
 				rp[i] = new RestParamDefaults.MethodObject(method, t);
 			}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamDefaults.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamDefaults.java
index 3e1480e..11ada55 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamDefaults.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamDefaults.java
@@ -820,18 +820,6 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class PathRemainderObject extends RestMethodParam {
-
-		protected PathRemainderObject(Method method, Type type) {
-			super(OTHER, method, null, type);
-		}
-
-		@Override /* RestMethodParam */
-		public Object resolve(RestRequest req, RestResponse res) throws Exception {
-			return ClassUtils.fromString(getTypeClass(), req.getPathMatch().getRemainder());
-		}
-	}
-
 	static final class RestRequestPropertiesObject extends RestMethodParam {
 
 		protected RestRequestPropertiesObject() {
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
index aeec43c..eaf0a0f 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
@@ -620,7 +620,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	 * 	<li>
 	 * 		The {@link RequestPathMatch} object can also be passed as a parameter on the method.
 	 * 	<li>
-	 * 		The {@link Path @Path} and {@link PathRemainder @PathRemainder} annotations can be used to access individual values.
+	 * 		The {@link Path @Path} annotation can be used to access individual values.
 	 * </ul>
 	 *
 	 * <h5 class='section'>See Also:</h5>
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/PathsTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/PathsTest.java
index be3be71..40fd1d6 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/PathsTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/PathsTest.java
@@ -52,7 +52,7 @@ public class PathsTest {
 	@RestResource
 	public static class A {
 		@RestMethod(name=GET)
-		public ObjectMap get(RestRequest req, @PathRemainder String r) {
+		public ObjectMap get(RestRequest req, @Path("/*") String r) {
 			return getPaths(req).append("pathRemainder2", r).append("method",1);
 		}
 	}
@@ -200,7 +200,7 @@ public class PathsTest {
 
 	public static class B {
 		@RestMethod(name=GET, path="/subpath/*")
-		public ObjectMap get(RestRequest req, @PathRemainder String r) {
+		public ObjectMap get(RestRequest req, @Path("/*") String r) {
 			return getPaths(req).append("pathRemainder2", r).append("method",2);
 		}
 	}
@@ -352,7 +352,7 @@ public class PathsTest {
 	@RestResource(path="/a")
 	public static class C01 {
 		@RestMethod(name=GET)
-		public ObjectMap get(RestRequest req, @PathRemainder String r) {
+		public ObjectMap get(RestRequest req, @Path("/*") String r) {
 			return getPaths(req).append("pathRemainder2", r).append("method",3);
 		}
 	}
@@ -504,7 +504,7 @@ public class PathsTest {
 	@RestResource(path="/a")
 	public static class D01 {
 		@RestMethod(name=GET, path="/subpath/*")
-		public ObjectMap get(RestRequest req, @PathRemainder String r) {
+		public ObjectMap get(RestRequest req, @Path("/*") String r) {
 			return getPaths(req).append("pathRemainder2", r).append("method",4);
 		}
 	}
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/PathAnnotationTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/PathAnnotationTest.java
index ec878af..1f88c7a 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/PathAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/PathAnnotationTest.java
@@ -66,7 +66,7 @@ public class PathAnnotationTest {
 			return "GET /a " + foo + "," + bar;
 		}
 		@RestMethod(name=GET, path="/a/{foo}/{bar}/*")
-		public String simplePathWithRemainder(@Path("foo") String foo, @Path("bar") int bar, @PathRemainder String remainder) {
+		public String simplePathWithRemainder(@Path("foo") String foo, @Path("bar") int bar, @Path("/*") String remainder) {
 			return "GET /a "+foo+","+bar+",r="+remainder;
 		}
 	}
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/PathRemainderAnnotationTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/PathRemainderAnnotationTest.java
index 8c5ca33..57b1799 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/PathRemainderAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/PathRemainderAnnotationTest.java
@@ -33,7 +33,7 @@ public class PathRemainderAnnotationTest {
 	@RestResource
 	public static class A  {
 		@RestMethod(name=GET, path="/*")
-		public String b(@PathRemainder String remainder) {
+		public String b(@Path("/*") String remainder) {
 			return remainder;
 		}
 	}