juneau-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jamesbog...@apache.org
Subject [juneau] branch master updated: Swagger UI enhancements.
Date Sun, 08 Apr 2018 21:55:23 GMT
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 d666a02  Swagger UI enhancements.
d666a02 is described below

commit d666a02e2aa08693c69a69dcc782f380deed8071
Author: JamesBognar <jamesbognar@apache.org>
AuthorDate: Sun Apr 8 14:54:57 2018 -0700

    Swagger UI enhancements.
---
 .../org/apache/juneau/dto/swagger/SwaggerTest.java |   8 +-
 .../apache/juneau/dto/swagger/OperationMap.java    |  68 +++++--
 .../org/apache/juneau/dto/swagger/Swagger.java     |  40 +---
 .../apache/juneau/dto/swagger/ui/SwaggerUI.java    |   3 +-
 .../jsonschema/JsonSchemaSerializerSession.java    |   3 +
 juneau-doc/src/main/javadoc/overview.html          |   4 +-
 .../examples/rest/SystemPropertiesResource.java    | 117 ++++++------
 .../rest/petstore/IdConflictException.java         |   2 +-
 .../rest/petstore/IdNotFoundException.java         |   2 +-
 .../examples/rest/petstore/InvalidIdException.java |   2 +-
 .../rest/petstore/InvalidTagException.java         |   2 +-
 .../rest/petstore/InvalidUsernameException.java    |   2 +-
 .../examples/rest/petstore/LoginException.java     |   2 +-
 .../examples/rest/petstore/PetStoreResource.java   | 166 ++++++++--------
 .../apache/juneau/rest/test/HeadersResource.java   |   2 +-
 .../apache/juneau/rest/BasicRestCallHandler.java   |   4 +-
 .../apache/juneau/rest/BasicRestInfoProvider.java  | 120 +++++++-----
 .../main/java/org/apache/juneau/rest/Redirect.java |   2 +-
 .../java/org/apache/juneau/rest/RestContext.java   |  54 ++++--
 .../org/apache/juneau/rest/RestContextBuilder.java |   4 +-
 .../org/apache/juneau/rest/RestJavaMethod.java     |  28 ++-
 .../rest/{RestParam.java => RestMethodParam.java}  |   6 +-
 .../org/apache/juneau/rest/RestMethodReturn.java   |  62 +++++-
 .../org/apache/juneau/rest/RestMethodThrown.java   |  61 +++++-
 .../org/apache/juneau/rest/RestParamDefaults.java  | 212 ++++++++++-----------
 .../{RestStatus.java => ResponseInfo.java}         |  36 +++-
 .../juneau/rest/annotation/RestResource.java       |   2 +-
 27 files changed, 605 insertions(+), 409 deletions(-)

diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/dto/swagger/SwaggerTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/dto/swagger/SwaggerTest.java
index 06fa9ab..95553e5 100644
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/dto/swagger/SwaggerTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/dto/swagger/SwaggerTest.java
@@ -287,11 +287,11 @@ public class SwaggerTest {
 	public void testSetPaths() {
 		Swagger t = new Swagger();
 		
-		t.setPaths(new AMap<String,Map<String,Operation>>().append("foo", new AMap<String,Operation>().append("bar",operation().summary("baz"))));
+		t.setPaths(new AMap<String,OperationMap>().append("foo", new OperationMap().append("bar",operation().summary("baz"))));
 		assertObjectEquals("{foo:{bar:{summary:'baz'}}}", t.getPaths());
 		assertType(Map.class, t.getPaths());
 		
-		t.setPaths(new AMap<String,Map<String,Operation>>());
+		t.setPaths(new AMap<String,OperationMap>());
 		assertObjectEquals("{}", t.getPaths());
 		assertType(Map.class, t.getPaths());
 
@@ -306,11 +306,11 @@ public class SwaggerTest {
 	public void testAddPaths() {
 		Swagger t = new Swagger();
 		
-		t.addPaths(new AMap<String,Map<String,Operation>>().append("foo", new AMap<String,Operation>().append("bar",operation().summary("baz"))));
+		t.addPaths(new AMap<String,OperationMap>().append("foo", new OperationMap().append("bar",operation().summary("baz"))));
 		assertObjectEquals("{foo:{bar:{summary:'baz'}}}", t.getPaths());
 		assertType(Map.class, t.getPaths());
 		
-		t.addPaths(new AMap<String,Map<String,Operation>>());
+		t.addPaths(new AMap<String,OperationMap>());
 		assertObjectEquals("{foo:{bar:{summary:'baz'}}}", t.getPaths());
 		assertType(Map.class, t.getPaths());
 
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/IdConflictException.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/OperationMap.java
similarity index 50%
copy from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/IdConflictException.java
copy to juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/OperationMap.java
index a69bd25..f7cae77 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/IdConflictException.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/OperationMap.java
@@ -10,25 +10,71 @@
 // * "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.examples.rest.petstore;
+package org.apache.juneau.dto.swagger;
 
-import org.apache.juneau.*;
-import org.apache.juneau.rest.annotation.*;
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.util.*;
+
+import org.apache.juneau.utils.*;
 
 /**
- * Exception thrown when trying to add an entry where the ID is already in use.
+ * Map meant for method-name/operation mappings.
+ * 
+ * <p>
+ * Forces entries to be sorted in the following order:
+ * <ul>
+ * 	<li><code>GET</code>
+ * 	<li><code>PUT</code>
+ * 	<li><code>POST</code>
+ * 	<li><code>DELETE</code>
+ * 	<li><code>OPTIONS</code>
+ * 	<li><code>HEAD</code>
+ * 	<li><code>PATCH</code>
+ * 	<li>Everything else.
+ * </ul>
  */
-@SuppressWarnings("serial")
-@RestStatus(value=409, description="ID already in use")
-public class IdConflictException extends FormattedException {
+public class OperationMap extends TreeMap<String,Operation> {
+	private static final long serialVersionUID = 1L;
+
+	private static final Comparator<String> OP_SORTER = new Comparator<String>() {
+		private final Map<String,Integer> methods = new AMap<String,Integer>()
+			.append("get",7)
+			.append("put",6)
+			.append("post",5)
+			.append("delete",4)
+			.append("options",3)
+			.append("head",2)
+			.append("patch",1);
+
+		@Override
+		public int compare(String o1, String o2) {
+			Integer i1 = methods.get(o1);
+			Integer i2 = methods.get(o2);
+			if (i1 == null)
+				i1 = 0;
+			if (i2 == null)
+				i2 = 0;
+			return i2.compareTo(i1);
+		}
+	};
 
 	/**
 	 * Constructor.
+	 */
+	public OperationMap() {
+		super(OP_SORTER);
+	}
+	
+	/**
+	 * Fluent-style {@link #put(String, Operation)} method.
 	 * 
-	 * @param id The duplicate ID.
-	 * @param c The object type..
+	 * @param httpMethodName The HTTP method name.
+	 * @param operation The operation.
+	 * @return This method (for method chaining).
 	 */
-	public IdConflictException(Object id, Class<?> c) {
-		super("ID ''{0}'' already in use for type ''{1}''", id, c.getSimpleName());
+	public OperationMap append(String httpMethodName, Operation operation) {
+		put(emptyIfNull(httpMethodName).toLowerCase(), operation);
+		return this;
 	}
 }
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Swagger.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Swagger.java
index 004eaa8..209e50d 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Swagger.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Swagger.java
@@ -54,7 +54,7 @@ public class Swagger extends SwaggerElement {
 	private Map<String,ParameterInfo> parameters;
 	private Map<String,ResponseInfo> responses;
 	private Map<String,SecurityScheme> securityDefinitions;
-	private Map<String,Map<String,Operation>> paths;
+	private Map<String,OperationMap> paths;
 
 	/**
 	 * Default constructor.
@@ -113,10 +113,10 @@ public class Swagger extends SwaggerElement {
 			for (Map.Entry<String,SecurityScheme> e : copyFrom.securityDefinitions.entrySet())
 				this.securityDefinitions.put(e.getKey(), e.getValue().copy());
 
-		this.paths = copyFrom.paths == null ? null : new LinkedHashMap<String,Map<String,Operation>>();
+		this.paths = copyFrom.paths == null ? null : new LinkedHashMap<String,OperationMap>();
 		if (copyFrom.paths != null)
-			for (Map.Entry<String,Map<String,Operation>> e : copyFrom.paths.entrySet()) {
-				Map<String,Operation> m = new LinkedHashMap<>();
+			for (Map.Entry<String,OperationMap> e : copyFrom.paths.entrySet()) {
+				OperationMap m = new OperationMap();
 				for (Map.Entry<String,Operation> e2 : e.getValue().entrySet())
 					m.put(e2.getKey(), e2.getValue().copy());
 				this.paths.put(e.getKey(), m);
@@ -602,7 +602,7 @@ public class Swagger extends SwaggerElement {
 	 * 
 	 * @return The property value, or <jk>null</jk> if it is not set.
 	 */
-	public Map<String,Map<String,Operation>> getPaths() {
+	public Map<String,OperationMap> getPaths() {
 		return paths;
 	}
 
@@ -617,7 +617,7 @@ public class Swagger extends SwaggerElement {
 	 * 	<br>Property value is required.
 	 * @return This object (for method chaining).
 	 */
-	public Swagger setPaths(Map<String,Map<String,Operation>> value) {
+	public Swagger setPaths(Map<String,OperationMap> value) {
 		paths = newSortedMap(value, null);
 		return this;
 	}
@@ -636,7 +636,7 @@ public class Swagger extends SwaggerElement {
 	 * 	<br>Ignored if <jk>null</jk>.
 	 * @return This object (for method chaining).
 	 */
-	public Swagger addPaths(Map<String,Map<String,Operation>> values) {
+	public Swagger addPaths(Map<String,OperationMap> values) {
 		paths = addToSortedMap(paths, values, null);
 		return this;
 	}
@@ -652,9 +652,9 @@ public class Swagger extends SwaggerElement {
 	public Swagger path(String path, String methodName, Operation operation) {
 		if (paths == null)
 			paths = new TreeMap<>();
-		Map<String,Operation> p = paths.get(path);
+		OperationMap p = paths.get(path);
 		if (p == null) {
-			p = new TreeMap<>(OP_SORTER);
+			p = new OperationMap();
 			paths.put(path, p);
 		}
 		p.put(methodName, operation);
@@ -1338,28 +1338,6 @@ public class Swagger extends SwaggerElement {
 		return new MultiSet<>(s, super.keySet());
 	}
 	
-	private static final Comparator<String> OP_SORTER = new Comparator<String>() {
-		private final Map<String,Integer> methods = new AMap<String,Integer>()
-			.append("get",7)
-			.append("put",6)
-			.append("post",5)
-			.append("delete",4)
-			.append("options",3)
-			.append("head",2)
-			.append("patch",1);
-
-		@Override
-		public int compare(String o1, String o2) {
-			Integer i1 = methods.get(o1);
-			Integer i2 = methods.get(o2);
-			if (i1 == null)
-				i1 = 0;
-			if (i2 == null)
-				i2 = 0;
-			return i2.compareTo(i1);
-		}
-	};
-
 	@Override /* Object */
 	public String toString() {
 		return JsonSerializer.DEFAULT.toString(this);
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ui/SwaggerUI.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ui/SwaggerUI.java
index 177e5ad..5697d16 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ui/SwaggerUI.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ui/SwaggerUI.java
@@ -80,7 +80,6 @@ public class SwaggerUI extends PojoSwap<Swagger,Div> {
 		Session(BeanSession bs, Swagger swagger) {
 			this.swagger = swagger.copy();
 			this.resolveRefsMaxDepth = bs.getProperty(SWAGGERUI_resolveRefsMaxDepth, Integer.class, 1);
-			System.err.println("resolveRefsMaxDepth=" + resolveRefsMaxDepth);
 		}
 	}
 	
@@ -180,7 +179,7 @@ public class SwaggerUI extends PojoSwap<Swagger,Div> {
 	private Div tagBlockContents(Session s, Tag t) {
 		Div tagBlockContents = div()._class("tag-block-contents");
 		
-		for (Map.Entry<String,Map<String,Operation>> e : s.swagger.getPaths().entrySet()) {
+		for (Map.Entry<String,OperationMap> e : s.swagger.getPaths().entrySet()) {
 			String path = e.getKey();
 			for (Map.Entry<String,Operation> e2 : e.getValue().entrySet()) {
 				String opName = e2.getKey();
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaSerializerSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaSerializerSession.java
index c9032a7..1b3a19b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaSerializerSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaSerializerSession.java
@@ -178,6 +178,9 @@ public class JsonSchemaSerializerSession extends JsonSerializerSession {
 			tc = STRING;
 			type = "string";
 			format = "uri";
+		} else {
+			tc = STRING;
+			type = "string";
 		}
 
 		// Add info from @JsonSchema on bean property.
diff --git a/juneau-doc/src/main/javadoc/overview.html b/juneau-doc/src/main/javadoc/overview.html
index ea2213e..1efcf80 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -21370,8 +21370,8 @@
 			<li>
 				Newlines were being stripped from <code><ja>@HtmlDoc</ja>(script)</code> when serialized which could cause script lines to become commented out.
 			<li>
-				New {@link org.apache.juneau.rest.annotation.RestStatus @RestStatus} annotation that can be applied to
-				throwables thrown from REST methods to specify non-200 status return codes and descriptions in Swagger documentation.
+				New {@link org.apache.juneau.rest.annotation.ResponseInfo @ResponseInfo} annotation that can be applied to
+				throwables thrown from REST methods and POJOs returned by REST methods to specify non-200 status return codes and descriptions in Swagger documentation.
 			<li>
 				Swagger fields added to the following annotations:
 				<ul class='doctree'>
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SystemPropertiesResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SystemPropertiesResource.java
index 6c67d75..ca27d3f 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SystemPropertiesResource.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SystemPropertiesResource.java
@@ -14,7 +14,6 @@ package org.apache.juneau.examples.rest;
 
 import static org.apache.juneau.dto.html5.HtmlBuilder.*;
 import static org.apache.juneau.http.HttpMethodName.*;
-import static org.apache.juneau.serializer.WriterSerializer.*;
 
 import java.util.*;
 import java.util.Map;
@@ -72,19 +71,19 @@ import org.apache.juneau.rest.widget.*;
 	// Properties that get applied to all serializers and parsers.
 	properties={
 		// Use single quotes.
-		@Property(name=WSERIALIZER_quoteChar, value="'")
 	},
 
 	// Support GZIP encoding on Accept-Encoding header.
 	encoders=GzipEncoder.class,
 
 	swagger={
-		"contact:{name:'John Smith',email:'john@smith.com'},",
-		"license:{name:'Apache 2.0',url:'http://www.apache.org/licenses/LICENSE-2.0.html'},",
-		"version:'2.0',",
-		"termsOfService:'You are on your own.',",
-		"tags:[{name:'Java',description:'Java utility'}],",
-		"externalDocs:{description:'Home page',url:'http://juneau.apache.org'}"
+		"info: {",
+			"contact:{name:'Juneau Developer',email:'dev@juneau.apache.org'},",
+			"license:{name:'Apache 2.0',url:'http://www.apache.org/licenses/LICENSE-2.0.html'},",
+			"version:'2.0',",
+			"termsOfService:'You are on your own.'",
+		"},",
+		"externalDocs:{description:'Apache Juneau',url:'http://juneau.apache.org'}"
 	}
 )
 public class SystemPropertiesResource extends BasicRestServlet {
@@ -95,16 +94,16 @@ public class SystemPropertiesResource extends BasicRestServlet {
 		summary="Show all system properties",
 		description="Returns all system properties defined in the JVM.",
 		swagger={
-			"parameters:[",
-				"{name:'sort',in:'query',description:'Sort results alphabetically',default:'false'}",
-			"],",
 			"responses:{",
-				"200: {description:'Returns a map of key/value pairs.'}",
+				"200: {description:'Returns a map of key/value pairs.', x-example:{key1:'val1',key2:'val2'}}",
 			"}"
 		}
 	)
 	@SuppressWarnings({"rawtypes", "unchecked"})
-	public Map getSystemProperties(@Query("sort") boolean sort) throws Throwable {
+	public Map getSystemProperties(
+			@Query(name="sort", description="Sort results alphabetically", _default="false", example="true") boolean sort
+		) {
+
 		if (sort)
 			return new TreeMap(System.getProperties());
 		return System.getProperties();
@@ -115,15 +114,15 @@ public class SystemPropertiesResource extends BasicRestServlet {
 		summary="Get system property",
 		description="Returns the value of the specified system property.",
 		swagger={
-			"parameters:[",
-				"{name:'propertyName',in:'path',description:'The system property name.'}",
-			"],",
 			"responses:{",
 				"200: {description:'The system property value, or null if not found.'}",
 			"}"
 		}
 	)
-	public String getSystemProperty(@Path String propertyName) throws Throwable {
+	public String getSystemProperty(
+			@Path(description="The system property name.", example="PATH") String propertyName
+		) throws Throwable {
+		
 		return System.getProperty(propertyName);
 	}
 
@@ -131,62 +130,43 @@ public class SystemPropertiesResource extends BasicRestServlet {
 		name=PUT, path="/{propertyName}",
 		summary="Replace system property",
 		description="Sets a new value for the specified system property.",
-		guards=AdminGuard.class,
-		swagger={
-			"parameters:[",
-				"{name:'propertyName',in:'path',description:'The system property name.'},",
-				"{in:'body',description:'The new system property value.'}",
-			"],",
-			"responses:{",
-				"302: {headers:{Location:{description:'The root URL of this resource.'}}},",
-				"403: {description:'User is not an admin.'}",
-			"}"
-		}
+		guards=AdminGuard.class
 	)
-	public Redirect setSystemProperty(@Path String propertyName, @Body String value) {
+	public RedirectToRoot setSystemProperty(
+			@Path(description="The system property name") String propertyName, 
+			@Body(description="The new system property value") String value
+		) throws UserNotAdminException {
+		
 		System.setProperty(propertyName, value);
-		return new Redirect("servlet:/");
+		return new RedirectToRoot();
 	}
 
 	@RestMethod(
 		name=POST, path="/",
 		summary="Add an entire set of system properties",
 		description="Takes in a map of key/value pairs and creates a set of new system properties.",
-		guards=AdminGuard.class,
-		swagger={
-			"parameters:[",
-				"{name:'propertyName',in:'path',description:'The system property name.'},",
-				"{in:'body',description:'The new system property values.',schema:{example:{key1:'val1',key2:123}}}",
-			"],",
-			"responses:{",
-				"302: {headers:{Location:{description:'The root URL of this resource.'}}},",
-				"403: {description:'User is not an admin.'}",
-			"}"
-		}
+		guards=AdminGuard.class
 	)
-	public Redirect setSystemProperties(@Body java.util.Properties newProperties) {
+	public RedirectToRoot setSystemProperties(
+			@Body(description="The new system property values", example="{key1:'val1',key2:123}") java.util.Properties newProperties
+		) throws UserNotAdminException {
+		
 		System.setProperties(newProperties);
-		return new Redirect("servlet:/");
+		return new RedirectToRoot();
 	}
 
 	@RestMethod(
 		name=DELETE, path="/{propertyName}",
 		summary="Delete system property",
 		description="Deletes the specified system property.",
-		guards=AdminGuard.class,
-		swagger={
-			"parameters:[",
-				"{name:'propertyName',in:'path',description:'The system property name.'}",
-			"],",
-			"responses:{",
-				"302: {headers:{Location:{description:'The root URL of this resource.'}}},",
-				"403: {description:'User is not an admin.'}",
-			"}"
-		}
+		guards=AdminGuard.class
 	)
-	public Redirect deleteSystemProperty(@Path String propertyName) {
+	public RedirectToRoot deleteSystemProperty(
+			@Path(description="The system property name") String propertyName
+		) throws UserNotAdminException {
+		
 		System.clearProperty(propertyName);
-		return new Redirect("servlet:/");
+		return new RedirectToRoot();
 	}
 
 	@RestMethod(
@@ -221,11 +201,34 @@ public class SystemPropertiesResource extends BasicRestServlet {
 
 	@RestMethod(
 		name=POST, path="/formPagePost",
+		summary="Form page post",
 		description="Accepts a simple form post of a system property name/value pair.",
 		guards=AdminGuard.class
 	)
-	public Redirect formPagePost(@FormData("name") String name, @FormData("value") String value) {
+	public RedirectToRoot formPagePost(@FormData("name") String name, @FormData("value") String value) throws UserNotAdminException {
 		System.setProperty(name, value);
-		return new Redirect("servlet:/");
+		return new RedirectToRoot();
+	}
+	
+	
+	//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+	// Beans
+	//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+	
+	@ResponseInfo(code=403, description="User is not an administrator.")
+	public static class UserNotAdminException extends RuntimeException {
+		private static final long serialVersionUID = 1L;
+
+		public UserNotAdminException() {
+			super("User is not an administrator");
+		}
+	}
+
+	@ResponseInfo(code=302, description="Redirect to root.", headers={"Location:{description:'Redirect URI', type:'string'}"}, schema="IGNORE")
+	public static class RedirectToRoot extends Redirect {
+		public RedirectToRoot() {
+			super("servlet:/");
+		}
 	}
+	
 }
\ No newline at end of file
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/IdConflictException.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/IdConflictException.java
index a69bd25..e425cfb 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/IdConflictException.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/IdConflictException.java
@@ -19,7 +19,7 @@ import org.apache.juneau.rest.annotation.*;
  * Exception thrown when trying to add an entry where the ID is already in use.
  */
 @SuppressWarnings("serial")
-@RestStatus(value=409, description="ID already in use")
+@ResponseInfo(code=409, description="ID already in use")
 public class IdConflictException extends FormattedException {
 
 	/**
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/IdNotFoundException.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/IdNotFoundException.java
index 27b69e7..9040425 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/IdNotFoundException.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/IdNotFoundException.java
@@ -19,7 +19,7 @@ import org.apache.juneau.rest.annotation.*;
  * Exception thrown when trying to add an entry where the ID is already in use.
  */
 @SuppressWarnings("serial")
-@RestStatus(value=404, description="ID not found")
+@ResponseInfo(code=404, description="ID not found")
 public class IdNotFoundException extends FormattedException {
 
 	/**
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/InvalidIdException.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/InvalidIdException.java
index c0f022a..c87bc46 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/InvalidIdException.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/InvalidIdException.java
@@ -18,7 +18,7 @@ import org.apache.juneau.rest.annotation.*;
  * Exception thrown when trying to add an entry where the ID is already in use.
  */
 @SuppressWarnings("serial")
-@RestStatus(value=400, description="Invalid ID provided")
+@ResponseInfo(code=400, description="Invalid ID provided")
 public class InvalidIdException extends Exception {
 
 	/**
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/InvalidTagException.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/InvalidTagException.java
index 407ad82..400c09b 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/InvalidTagException.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/InvalidTagException.java
@@ -18,7 +18,7 @@ import org.apache.juneau.rest.annotation.*;
  * Exception thrown when trying to add an entry where the ID is already in use.
  */
 @SuppressWarnings("serial")
-@RestStatus(value=400, description="Invalid tag provided")
+@ResponseInfo(code=400, description="Invalid tag provided")
 public class InvalidTagException extends Exception {
 
 	/**
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/InvalidUsernameException.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/InvalidUsernameException.java
index 4d01a91..0dec4c2 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/InvalidUsernameException.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/InvalidUsernameException.java
@@ -18,7 +18,7 @@ import org.apache.juneau.rest.annotation.*;
  * Exception thrown when trying to add an entry where the ID is already in use.
  */
 @SuppressWarnings("serial")
-@RestStatus(value=400, description="Invalid username provided")
+@ResponseInfo(code=400, description="Invalid username provided")
 public class InvalidUsernameException extends Exception {
 
 	/**
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/LoginException.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/LoginException.java
index 9fedc05..b6f2bf4 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/LoginException.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/LoginException.java
@@ -18,7 +18,7 @@ import org.apache.juneau.rest.annotation.*;
  * Exception thrown when an invalid username or password is provided.
  */
 @SuppressWarnings("serial")
-@RestStatus(value=401, description="Invalid username or password provided")
+@ResponseInfo(code=401, description="Invalid username or password provided")
 public class LoginException extends Exception {
 	
 	/**
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStoreResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStoreResource.java
index fe93b0a..f81a0ff 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStoreResource.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/PetStoreResource.java
@@ -95,7 +95,10 @@ public class PetStoreResource extends BasicRestServletJena {
 			"security:[ { api_key:[] } ]"
 		}
 	)
-	public Pet getPet(@Path(description="ID of pet to return", example="123") long petId) throws IdNotFoundException {
+	public Pet getPet(
+			@Path(description="ID of pet to return", example="123") long petId
+		) throws IdNotFoundException {
+		
 		return db.getPet(petId);
 	}
 	
@@ -105,16 +108,15 @@ public class PetStoreResource extends BasicRestServletJena {
 		summary="Add a new pet to the store",
 		swagger={
 			"tags:['pet'],",
-			"security:[ { petstore_auth:['write:pets','read:pets'] } ],",
-			"responses: { 200: { 'x-example':'OK' } }"
+			"security:[ { petstore_auth:['write:pets','read:pets'] } ]"
 		}
 	)
-	public String addPet(
+	public Ok addPet(
 			@Body(description="Pet object that needs to be added to the store") Pet pet
 		) throws IdConflictException {
 		
 		db.add(pet);
-		return "OK";
+		return OK;
 	}
 	
 	@RestMethod(
@@ -123,13 +125,15 @@ public class PetStoreResource extends BasicRestServletJena {
 		summary="Update an existing pet",
 		swagger={
 			"tags:['pet'],",
-			"security:[ { petstore_auth: ['write:pets','read:pets'] } ],",
-			"responses: { 200: { 'x-example':'OK' } }"
+			"security:[ { petstore_auth: ['write:pets','read:pets'] } ]"
 		}
 	)
-	public String updatePet(@Body(description="Pet object that needs to be added to the store") Pet pet) throws IdNotFoundException {
+	public Ok updatePet(
+			@Body(description="Pet object that needs to be added to the store") Pet pet
+		) throws IdNotFoundException {
+		
 		db.update(pet);
-		return "OK";
+		return OK;
 	}
 
 	@RestMethod(
@@ -185,11 +189,10 @@ public class PetStoreResource extends BasicRestServletJena {
 		summary="Updates a pet in the store with form data",
 		swagger={
 			"tags:[ 'pet' ],",
-			"security:[ { petstore_auth:[ 'write:pets', 'read:pets' ] } ],",
-			"responses: { 200: { 'x-example':'OK' } }"
+			"security:[ { petstore_auth:[ 'write:pets', 'read:pets' ] } ]"
 		}
 	)
-	public String updatePetForm(
+	public Ok updatePetForm(
 			@Path(description="ID of pet that needs to be updated", example="123") long petId, 
 			@FormData(name="name", description="Updated name of the pet", example="'Scruffy'") String name, 
 			@FormData(name="status", description="Updated status of the pet", example="'AVAILABLE'") PetStatus status
@@ -199,7 +202,7 @@ public class PetStoreResource extends BasicRestServletJena {
 		pet.name(name);
 		pet.status(status);
 		db.update(pet);
-		return "OK";
+		return OK;
 	}
 
 	@RestMethod(
@@ -208,16 +211,16 @@ public class PetStoreResource extends BasicRestServletJena {
 		summary="Deletes a pet",
 		swagger={
 			"tags:[ 'pet' ],",
-			"security:[ { petstore_auth:[ 'write:pets','read:pets' ] } ],",
-			"responses: { 200: { 'x-example':'OK' } }"
+			"security:[ { petstore_auth:[ 'write:pets','read:pets' ] } ]"
 		}
 	)
-	public String deletePet(
+	public Ok deletePet(
 			@Header(name="api_key", example="foobar") String apiKey, 
 			@Path(description="Pet id to delete", example="123") long petId
 		) throws IdNotFoundException {
+		
 		db.removePet(petId);
-		return "OK";
+		return OK;
 	}
 
 	@RestMethod(
@@ -226,16 +229,16 @@ public class PetStoreResource extends BasicRestServletJena {
 		summary="Uploads an image",
 		swagger={
 			"tags:[ 'pet' ],",
-			"security:[ { petstore_auth:[ 'write:pets','read:pets' ] } ],",
-			"responses: { 200: { 'x-example':'OK' } }"
+			"security:[ { petstore_auth:[ 'write:pets','read:pets' ] } ]"
 		}
 	)
-	public String uploadImage(
+	public Ok uploadImage(
 			@Path(description="ID of pet to update", example="123") long petId, 
 			@FormData(name="additionalMetadata", description="Additional data to pass to server", example="Foobar") String additionalMetadata, 
 			@FormData(name="file", description="file to upload", required="true", type="file") byte[] file
 		) {
-		return "OK";
+		
+		return OK;
 	}
 
 	//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -264,13 +267,7 @@ public class PetStoreResource extends BasicRestServletJena {
 		}
 	)
 	public Order getOrder(
-			@Path(
-				description="ID of order to fetch", 
-				maximum="10", 
-				minimum="1",
-				example="5"
-			) 
-			long orderId
+			@Path(description="ID of order to fetch", maximum="10", minimum="1", example="5") long orderId
 		) throws InvalidIdException, IdNotFoundException {
 		
 		if (orderId < 0 || orderId > 10)
@@ -287,11 +284,7 @@ public class PetStoreResource extends BasicRestServletJena {
 		}
 	)
 	public Order placeOrder(
-			@Body(
-				description="Order placed for purchasing the pet", 
-				example="{petId:456,quantity:100}"
-			) 
-			Order order
+			@Body(description="Order placed for purchasing the pet", example="{petId:456,quantity:100}") Order order
 		) throws IdConflictException {
 		
 		return db.add(order);
@@ -303,23 +296,17 @@ public class PetStoreResource extends BasicRestServletJena {
 		summary="Delete purchase order by ID",
 		description="For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors.",
 		swagger={
-			"tags:[ 'store' ],",
-			"responses: { 200: { 'x-example':'OK' } }"
+			"tags:[ 'store' ]"
 		}
 	)
-	public String deletePurchaseOrder(
-			@Path(
-				description="ID of the order that needs to be deleted", 
-				minimum="1",
-				example="5"
-			) 
-			long orderId
+	public Ok deletePurchaseOrder(
+			@Path(description="ID of the order that needs to be deleted", minimum="1", example="5") long orderId
 		) throws InvalidIdException, IdNotFoundException {
 		
 		if (orderId < 0)
 			throw new InvalidIdException();
 		db.removeOrder(orderId);
-		return "OK";
+		return OK;
 	}
 
 	@RestMethod(
@@ -360,10 +347,13 @@ public class PetStoreResource extends BasicRestServletJena {
 		path="/user/{username}",
 		summary="Get user by user name",
 		swagger={
-			"tags:[ 'user' ]",
+			"tags:[ 'user' ]"
 		}
 	)
-	public User getUser(@Path(description="The name that needs to be fetched. Use user1 for testing.") String username) throws InvalidUsernameException, IdNotFoundException {
+	public User getUser(
+			@Path(description="The name that needs to be fetched. Use user1 for testing.") String username
+		) throws InvalidUsernameException, IdNotFoundException {
+		
 		return db.getUser(username);
 	}
 	
@@ -373,13 +363,15 @@ public class PetStoreResource extends BasicRestServletJena {
 		summary="Create user",
 		description="This can only be done by the logged in user.",
 		swagger={
-			"tags:[ 'user' ],",
-			"responses: { 200: { 'x-example':'OK' } }"
+			"tags:[ 'user' ]"
 		}
 	)
-	public String createUser(@Body(description="Created user object") User user) throws InvalidUsernameException, IdConflictException {
+	public Ok createUser(
+			@Body(description="Created user object") User user
+		) throws InvalidUsernameException, IdConflictException {
+		
 		db.add(user);
-		return "OK";
+		return OK;
 	}
 
 	@RestMethod(
@@ -387,14 +379,16 @@ public class PetStoreResource extends BasicRestServletJena {
 		path="/user/createWithArray",
 		summary="Creates list of users with given input array",
 		swagger={
-			"tags:[ 'user' ],",
-			"responses: { 200: { 'x-example':'OK' } }"
+			"tags:[ 'user' ]"
 		}
 	)
-	public String createUsers(@Body(description="List of user objects") User[] users) throws InvalidUsernameException, IdConflictException {
+	public Ok createUsers(
+			@Body(description="List of user objects") User[] users
+		) throws InvalidUsernameException, IdConflictException {
+		
 		for (User user : users)
 			db.add(user);
-		return "OK";
+		return OK;
 	}
 
 	@RestMethod(
@@ -403,18 +397,18 @@ public class PetStoreResource extends BasicRestServletJena {
 		summary="Update user",
 		description="This can only be done by the logged in user.",
 		swagger={
-			"tags:[ 'user' ],",
-			"responses: { 200: { 'x-example':'OK' } }"
+			"tags:[ 'user' ]"
 		}
 	)
-	public String updateUser(
+	public Ok updateUser(
 			@Path(description="Name that need to be updated") String username, 
 			@Body(description="Updated user object") User user
 		) throws InvalidUsernameException, IdNotFoundException {
+		
 		User oldUser = db.getUser(username);
 		user.id(oldUser.getId());
 		db.update(user);
-		return "OK";
+		return OK;
 	}
 
 	@RestMethod(
@@ -423,14 +417,16 @@ public class PetStoreResource extends BasicRestServletJena {
 		summary="Delete user",
 		description="This can only be done by the logged in user.",
 		swagger={
-			"tags:[ 'user' ],",
-			"responses: { 200: { 'x-example':'OK' } }"
+			"tags:[ 'user' ]"
 		}
 	)
-	public String deleteUser(@Path(description="The name that needs to be deleted") String username) throws InvalidUsernameException, IdNotFoundException {
+	public Ok deleteUser(
+			@Path(description="The name that needs to be deleted") String username
+		) throws InvalidUsernameException, IdNotFoundException {
+		
 		User oldUser = db.getUser(username);
 		db.removeUser(oldUser.getId());
-		return "OK";
+		return OK;
 	}
 	
 	@RestMethod(
@@ -441,8 +437,6 @@ public class PetStoreResource extends BasicRestServletJena {
 			"tags:[ 'user' ],",
 			"responses:{",
 				"200:{",
-					"'x-example':'OK',",
-					"schema:{ type:'string' },",
 					"headers:{",
 						"X-Rate-Limit:{ type:'integer', format:'int32', description:'calls per hour allowed by the user', 'x-example':123},",
 						"X-Expires-After:{ type:'string', format:'date-time', description:'date in UTC when token expires', 'x-example':'2012-10-21'}",
@@ -451,21 +445,9 @@ public class PetStoreResource extends BasicRestServletJena {
 			"}"
 		}
 	)
-	public String login(
-			@Query(
-				name="username", 
-				description="The username for login", 
-				required="true", 
-				example="myuser"
-			) 
-			String username, 
-			@Query(
-				name="password", 
-				description="The password for login in clear text", 
-				required="true", 
-				example="abc123"
-			) 
-			String password, 
+	public Ok login(
+			@Query(name="username", description="The username for login", required="true", example="myuser") String username, 
+			@Query(name="password", description="The password for login in clear text", required="true", example="abc123") String password, 
 			RestRequest req, 
 			RestResponse res
 		) throws LoginException {
@@ -477,7 +459,7 @@ public class PetStoreResource extends BasicRestServletJena {
 		req.getSession().setAttribute("login-expires", d);
 		res.setHeader("X-Rate-Limit", "1000");
 		res.setHeader("X-Expires-After", DateUtils.formatDate(d));
-		return "OK";
+		return OK;
 	}
 
 	@RestMethod(
@@ -485,12 +467,30 @@ public class PetStoreResource extends BasicRestServletJena {
 		path="/user/logout",
 		summary="Logs out current logged in user session",
 		swagger={
-			"tags:[ 'user' ],",
-			"responses: { 200: { 'x-example':'OK' } }"
+			"tags:[ 'user' ]"
 		}
 	)
-	public String logout(RestRequest req) {
+	public Ok logout(RestRequest req) {
 		req.getSession().removeAttribute("login-expires");
-		return "OK";
+		return OK;
+	}
+	
+	//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+	// Helper beans
+	//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+	
+	static final Ok OK = new Ok();
+	
+	@ResponseInfo(code=200, example="'OK'")
+	public static class Ok {
+
+		@Override
+		public String toString() {
+			return "OK";
+		}
+		
+		public static Ok fromString(String s) {
+			return OK;
+		}
 	}
 }
\ No newline at end of file
diff --git a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/HeadersResource.java b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/HeadersResource.java
index e106639..4a2f4b9 100644
--- a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/HeadersResource.java
+++ b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/HeadersResource.java
@@ -151,7 +151,7 @@ public class HeadersResource extends RestServlet {
 		return customHeader.toString();
 	}
 
-	public static class CustomHeaderParam extends RestParam {
+	public static class CustomHeaderParam extends RestMethodParam {
 		public CustomHeaderParam() {
 			super(RestParamType.HEADER, "Custom", CustomHeader.class);
 		}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
index 4c0698d..1b8a3a5 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
@@ -190,8 +190,8 @@ public class BasicRestCallHandler implements RestCallHandler {
 			r1.setAttribute("ExecTime", System.currentTimeMillis() - startTime);
 			handleError(r1, r2, e);
 		} catch (Throwable e) {
-			RestStatus status = e.getClass().getAnnotation(RestStatus.class);
-			RestException e2 = new RestException(status == null ? SC_INTERNAL_SERVER_ERROR : status.value(), e);
+			ResponseInfo ri = e.getClass().getAnnotation(ResponseInfo.class);
+			RestException e2 = new RestException(ri == null || ri.code() == 0 ? SC_INTERNAL_SERVER_ERROR : ri.code(), e);
 			r1.setAttribute("Exception", e);
 			r1.setAttribute("ExecTime", System.currentTimeMillis() - startTime);
 			handleError(r1, r2, e2);
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java
index 887cc02..719392e 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java
@@ -185,10 +185,7 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 			RestResource r = e.getValue();
 			if (r.swagger().length > 0) {
 				try {
-					String json = vr.resolve(join(r.swagger(), '\n').trim());
-					if (! isObjectMap(json, true))
-						json = "{\n" + json + "\n}";
-					omSwagger.putAll(new ObjectMap(json));
+					omSwagger.putAll(parseObjectMap(vr.resolve(join(r.swagger(), '\n').trim()), true));
 				} catch (ParseException x) {
 					throw new SwaggerException(x, e.getKey(), "Malformed swagger JSON encountered in @RestResource(swagger).");
 				}
@@ -285,10 +282,7 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 			// Add @RestMethod(swagger)
 			if (rm.swagger().length > 0) {
 				try {
-					String json = vr.resolve(join(rm.swagger(), '\n').trim());
-					if (! isObjectMap(json, true))
-						json = "{\n" + json + "\n}";
-					op.putAll(new ObjectMap(json));
+					op.putAll(parseObjectMap( vr.resolve(join(rm.swagger(), '\n').trim()), true));
 				} catch (ParseException e) {
 					throw new SwaggerException(e, m, "Malformed swagger JSON encountered in @RestMethod(swagger).");
 				}
@@ -360,7 +354,7 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 			}
 			
 			// Finally, look for parameters defined on method.
-			for (RestParam mp : context.getRestParams(m)) {
+			for (RestMethodParam mp : context.getRestMethodParams(m)) {
 				
 				RestParamType in = mp.getParamType();
 				
@@ -378,49 +372,49 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 				
 				ObjectMap pi = mp.getMetaData();
 				if (pi.containsKeyNotEmpty("required"))
-					param.put("required", vr.resolve(pi.getString("required")));
+					param.appendIf(false, true, true, "required", vr.resolve(pi.getString("required")));
 				if (pi.containsKeyNotEmpty("description"))
-					param.put("description", vr.resolve(pi.getString("description")));
+					param.appendIf(false, true, true, "description", vr.resolve(pi.getString("description")));
 				if (pi.containsKeyNotEmpty("type"))
-					param.put("type", vr.resolve(pi.getString("type")));
+					param.appendIf(false, true, true, "type", vr.resolve(pi.getString("type")));
 				if (pi.containsKeyNotEmpty("format"))
-					param.put("format", vr.resolve(pi.getString("format")));
+					param.appendIf(false, true, true, "format", vr.resolve(pi.getString("format")));
 				if (pi.containsKeyNotEmpty("pattern"))
-					param.put("pattern", vr.resolve(pi.getString("pattern")));
+					param.appendIf(false, true, true, "pattern", vr.resolve(pi.getString("pattern")));
 				if (pi.containsKeyNotEmpty("collectionFormat"))
-					param.put("collectionFormat", vr.resolve(pi.getString("collectionFormat")));
+					param.appendIf(false, true, true, "collectionFormat", vr.resolve(pi.getString("collectionFormat")));
 				if (pi.containsKeyNotEmpty("maximum"))
-					param.put("maximum", vr.resolve(pi.getString("maximum")));
+					param.appendIf(false, true, true, "maximum", vr.resolve(pi.getString("maximum")));
 				if (pi.containsKeyNotEmpty("minimum"))
-					param.put("minimum", vr.resolve(pi.getString("minimum")));
+					param.appendIf(false, true, true, "minimum", vr.resolve(pi.getString("minimum")));
 				if (pi.containsKeyNotEmpty("multipleOf"))
-					param.put("multipleOf", vr.resolve(pi.getString("multipleOf")));
+					param.appendIf(false, true, true, "multipleOf", vr.resolve(pi.getString("multipleOf")));
 				if (pi.containsKeyNotEmpty("maxLength"))
-					param.put("maxLength", vr.resolve(pi.getString("maxLength")));
+					param.appendIf(false, true, true, "maxLength", vr.resolve(pi.getString("maxLength")));
 				if (pi.containsKeyNotEmpty("minLength"))
-					param.put("minLength", vr.resolve(pi.getString("minLength")));
+					param.appendIf(false, true, true, "minLength", vr.resolve(pi.getString("minLength")));
 				if (pi.containsKeyNotEmpty("maxItems"))
-					param.put("maxItems", vr.resolve(pi.getString("maxItems")));
+					param.appendIf(false, true, true, "maxItems", vr.resolve(pi.getString("maxItems")));
 				if (pi.containsKeyNotEmpty("minItems"))
-					param.put("minItems", vr.resolve(pi.getString("minItems")));
+					param.appendIf(false, true, true, "minItems", vr.resolve(pi.getString("minItems")));
 				if (pi.containsKeyNotEmpty("allowEmptyVals"))
-					param.put("allowEmptyVals", vr.resolve(pi.getString("allowEmptyVals")));
+					param.appendIf(false, true, true, "allowEmptyVals", vr.resolve(pi.getString("allowEmptyVals")));
 				if (pi.containsKeyNotEmpty("exclusiveMaximum"))
-					param.put("exclusiveMaximum", vr.resolve(pi.getString("exclusiveMaximum")));
+					param.appendIf(false, true, true, "exclusiveMaximum", vr.resolve(pi.getString("exclusiveMaximum")));
 				if (pi.containsKeyNotEmpty("exclusiveMimimum"))
-					param.put("exclusiveMimimum", vr.resolve(pi.getString("exclusiveMimimum")));
+					param.appendIf(false, true, true, "exclusiveMimimum", vr.resolve(pi.getString("exclusiveMimimum")));
 				if (pi.containsKeyNotEmpty("uniqueItems"))
-					param.put("uniqueItems", vr.resolve(pi.getString("uniqueItems")));
+					param.appendIf(false, true, true, "uniqueItems", vr.resolve(pi.getString("uniqueItems")));
 				if (pi.containsKeyNotEmpty("schema"))
-					param.put("schema", new ObjectMap(vr.resolve(pi.getString("schema"))));
+					param.appendIf(false, true, true, "schema", parseObjectMap(vr.resolve(pi.getString("schema")), false));
 				if (pi.containsKeyNotEmpty("default"))
-					param.put("default", JsonParser.DEFAULT.parse(vr.resolve(pi.getString("default")), Object.class));
+					param.appendIf(false, true, true, "default", JsonParser.DEFAULT.parse(vr.resolve(pi.getString("default")), Object.class));
 				if (pi.containsKeyNotEmpty("enum"))
-					param.put("enum", new ObjectList(vr.resolve(pi.getString("enum"))));
+					param.appendIf(false, true, true, "enum", parseObjectList(vr.resolve(pi.getString("enum")), false));
 				if (pi.containsKeyNotEmpty("items"))
-					param.put("items", new ObjectMap(vr.resolve(pi.getString("items"))));
+					param.appendIf(false, true, true, "items", new ObjectMap(vr.resolve(pi.getString("items"))));
 				if (pi.containsKeyNotEmpty("example"))
-					param.put("x-example", parse(vr.resolve(pi.getString("example"))));
+					param.appendIf(false, true, true, "x-example", parse(vr.resolve(pi.getString("example"))));
 				
 				if ((in == BODY || in == PATH) && ! param.containsKeyNotEmpty("required"))
 					param.put("required", true);
@@ -445,24 +439,42 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 				}
 			}
 			
-			// Gather responses from @RestStatus-annotated exceptions.
-			for (Class<?> t : m.getExceptionTypes()) {
-				RestStatus rs = t.getAnnotation(RestStatus.class);
-				if (rs != null) {
-					String httpCode = String.valueOf(rs.value());
-					if (! responses.containsKey(httpCode))
-						responses.put(httpCode, new ObjectMap().append("description", rs.description()));
+			// Gather responses from @ResponseInfo-annotated exceptions.
+			for (RestMethodThrown rt : context.getRestMethodThrowns(m)) {
+				int code = rt.getCode();
+				if (code != 0) {
+					ObjectMap om = responses.getObjectMap(String.valueOf(code), true);
+					
+					ObjectMap md = rt.getMetaData();
+					if (md.containsKeyNotEmpty("description"))
+						om.appendIf(false, true, true, "description", vr.resolve(md.getString("description")));
+					if (md.containsKeyNotEmpty("example"))
+						om.appendIf(false, true, true, "x-example", parse(vr.resolve(md.getString("example"))));
+					if (md.containsKeyNotEmpty("schema"))
+						om.appendIf(false, true, true, "schema", parseObjectMap(vr.resolve(md.getString("schema")), false));
+					if (md.containsKeyNotEmpty("headers")) {
+						om.appendIf(false, true, true, "headers", parseObjectList(vr.resolve(md.getString("headers")), false));
+					}
 				}
 			}
 			
-			ObjectMap okResponse = responses.getObjectMap("200");
-			if (okResponse == null)
-				okResponse = new ObjectMap();
+			RestMethodReturn r = context.getRestMethodReturn(m);
+			String rStatus = r.getCode() == 0 ? "200" : String.valueOf(r.getCode());
 			
-			okResponse.put("schema", getSchema(req, okResponse.getObjectMap("schema", true), js, m.getGenericReturnType()));
-			addXExamples(req, sm, okResponse, "ok", js, m.getGenericReturnType());
+			ObjectMap rom = responses.getObjectMap(rStatus, true);
+
+			ObjectMap rmd = r.getMetaData();
+			if (rmd.containsKeyNotEmpty("description"))
+				rom.appendIf(false, true, true, "description", vr.resolve(rmd.getString("description")));
+			if (rmd.containsKeyNotEmpty("example"))
+				rom.appendIf(false, true, true, "x-example", parse(vr.resolve(rmd.getString("example"))));
+			if (rmd.containsKeyNotEmpty("schema"))
+				rom.appendIf(false, true, true, "schema", parseObjectMap(vr.resolve(rmd.getString("schema")), false));
+			if (rmd.containsKeyNotEmpty("headers")) 
+				rom.appendIf(false, true, true, "headers", parseObjectMap(vr.resolve(rmd.getString("headers")), false));
 			
-			responses.put("200", okResponse);
+			rom.put("schema", getSchema(req, rom.getObjectMap("schema", true), js, m.getGenericReturnType()));
+			addXExamples(req, sm, rom, "ok", js, m.getGenericReturnType());
 
 			// Add default response descriptions.
 			for (Map.Entry<String,Object> e : responses.entrySet()) {
@@ -518,11 +530,29 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 			return JsonParser.DEFAULT.parse(s, Object.class);
 		return s;
 	}
+	
+	private ObjectMap parseObjectMap(String s, boolean ignoreCommentsAndWhitespace) throws ParseException {
+		s = s.trim();
+		if ("IGNORE".equalsIgnoreCase(s))
+			return new ObjectMap().append("ignore", true);
+		if (! isObjectMap(s, ignoreCommentsAndWhitespace))
+			s = "{" + s + "}";
+		return new ObjectMap(s);
+	}	
+
+	private ObjectList parseObjectList(String s, boolean ignoreCommentsAndWhitespace) throws ParseException {
+		if (! isObjectList(s, ignoreCommentsAndWhitespace))
+			s = "[" + s + "]";
+		return new ObjectList(s);
+	}	
 
 	private ObjectMap getSchema(RestRequest req, ObjectMap schema, JsonSchemaSerializerSession js, Type type) throws Exception {
 		BeanSession bs = req.getBeanSession();
 		ClassMeta<?> cm = bs.getClassMeta(type);
 		
+		if (schema.getBoolean("ignore", false))
+			return null;
+			
 		if (schema.containsKey("type") || schema.containsKey("$ref")) 
 			return schema;
 		
@@ -919,7 +949,7 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 
 		Swagger s = getSwagger(req);
 		if (s != null) {
-			Map<String,Map<String,Operation>> sp = s.getPaths();
+			Map<String,OperationMap> sp = s.getPaths();
 			if (sp != null) {
 				Map<String,Operation> spp = sp.get(method.getAnnotation(RestMethod.class).path());
 				if (spp != null)
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/Redirect.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/Redirect.java
index 14844bc..ce222f6 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/Redirect.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/Redirect.java
@@ -25,7 +25,7 @@ import java.text.*;
  * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.Redirect">Overview &gt; juneau-rest-server &gt; Redirect</a>
  * </ul>
  */
-public final class Redirect {
+public class Redirect {
 
 	private final int httpResponseCode;
 	private final URI uri;
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 8f9d611..2777171 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
@@ -1545,7 +1545,7 @@ public final class RestContext extends BeanContext {
 	 * <h5 class='section'>Property:</h5>
 	 * <ul>
 	 * 	<li><b>Name:</b>  <js>"RestContext.paramResolvers.lo"</js>
-	 * 	<li><b>Data type:</b>  <code>List&lt;{@link RestParam} | Class&lt;? <jk>extends</jk> {@link RestParam}&gt;&gt;</code>
+	 * 	<li><b>Data type:</b>  <code>List&lt;{@link RestMethodParam} | Class&lt;? <jk>extends</jk> {@link RestMethodParam}&gt;&gt;</code>
 	 * 	<li><b>Default:</b>  empty list
 	 * 	<li><b>Session-overridable:</b>  <jk>false</jk>
 	 * 	<li><b>Annotations:</b>  
@@ -1555,7 +1555,7 @@ public final class RestContext extends BeanContext {
 	 * 	<li><b>Methods:</b> 
 	 * 		<ul>
 	 * 			<li class='jm'>{@link RestContextBuilder#paramResolvers(Class...)}
-	 * 			<li class='jm'>{@link RestContextBuilder#paramResolvers(RestParam...)}
+	 * 			<li class='jm'>{@link RestContextBuilder#paramResolvers(RestMethodParam...)}
 	 * 		</ul>
 	 * </ul>
 	 * 
@@ -1570,7 +1570,7 @@ public final class RestContext extends BeanContext {
 	 * the following resolver:
 	 * <p class='bcode'>
 	 * 	<jc>// Define a parameter resolver for resolving MySpecialObject objects.</jc>
-	 * 	<jk>public class</jk> MyRestParam <jk>extends</jk> RestParam {
+	 * 	<jk>public class</jk> MyRestParam <jk>extends</jk> RestMethodParam {
 	 * 
 	 * 		<jc>// Must have no-arg constructor!</jc>
 	 * 		<jk>public</jk> MyRestParam() {
@@ -1624,7 +1624,7 @@ public final class RestContext extends BeanContext {
 	 * 	<li>
 	 * 		Inner classes of the REST resource class are allowed.
 	 * 	<li>
-	 * 		Refer to {@link RestParam} for the list of predefined parameter resolvers.
+	 * 		Refer to {@link RestMethodParam} for the list of predefined parameter resolvers.
 	 * </ul>
 	 */
 	public static final String REST_paramResolvers = PREFIX + "paramResolvers.lo";
@@ -2758,7 +2758,7 @@ public final class RestContext extends BeanContext {
 	private final Set<String> allowedMethodParams;
 
 	private final RestContextProperties properties;
-	private final Map<Class<?>,RestParam> paramResolvers;
+	private final Map<Class<?>,RestMethodParam> paramResolvers;
 	private final SerializerGroup serializers;
 	private final ParserGroup parsers;
 	private final HttpPartSerializer partSerializer;
@@ -2801,7 +2801,7 @@ public final class RestContext extends BeanContext {
 		startCallMethods,
 		endCallMethods,
 		destroyMethods;
-	private final RestParam[][]
+	private final RestMethodParam[][]
 		preCallMethodParams,
 		postCallMethodParams;
 	private final Class<?>[][]
@@ -2853,8 +2853,8 @@ public final class RestContext extends BeanContext {
 			guards = getInstanceArrayProperty(REST_guards, resource, RestGuard.class, new RestGuard[0], true, this);
 			responseHandlers = getInstanceArrayProperty(REST_responseHandlers, resource, ResponseHandler.class, new ResponseHandler[0], true, this);
 
-			Map<Class<?>,RestParam> _paramResolvers = new HashMap<>();
-			for (RestParam rp : getInstanceArrayProperty(REST_paramResolvers, RestParam.class, new RestParam[0], true, this)) 
+			Map<Class<?>,RestMethodParam> _paramResolvers = new HashMap<>();
+			for (RestMethodParam rp : getInstanceArrayProperty(REST_paramResolvers, RestMethodParam.class, new RestMethodParam[0], true, this)) 
 				_paramResolvers.put(rp.forClass(), rp);
 			paramResolvers = unmodifiableMap(_paramResolvers);
 			
@@ -2948,7 +2948,7 @@ public final class RestContext extends BeanContext {
 				_postInitMethods = new LinkedHashMap<>(),
 				_postInitChildFirstMethods = new LinkedHashMap<>(),
 				_destroyMethods = new LinkedHashMap<>();
-			List<RestParam[]>
+			List<RestMethodParam[]>
 				_preCallMethodParams = new ArrayList<>(),
 				_postCallMethodParams = new ArrayList<>();
 			List<Class<?>[]>
@@ -3110,8 +3110,8 @@ public final class RestContext extends BeanContext {
 			this.postInitMethods = _postInitMethods.values().toArray(new Method[_postInitMethods.size()]);
 			this.postInitChildFirstMethods = _postInitChildFirstMethods.values().toArray(new Method[_postInitChildFirstMethods.size()]);
 			this.destroyMethods = _destroyMethods.values().toArray(new Method[_destroyMethods.size()]);
-			this.preCallMethodParams = _preCallMethodParams.toArray(new RestParam[_preCallMethodParams.size()][]);
-			this.postCallMethodParams = _postCallMethodParams.toArray(new RestParam[_postCallMethodParams.size()][]);
+			this.preCallMethodParams = _preCallMethodParams.toArray(new RestMethodParam[_preCallMethodParams.size()][]);
+			this.postCallMethodParams = _postCallMethodParams.toArray(new RestMethodParam[_postCallMethodParams.size()][]);
 			this.startCallMethodParams = _startCallMethodParams.toArray(new Class[_startCallMethodParams.size()][]);
 			this.endCallMethodParams = _endCallMethodParams.toArray(new Class[_endCallMethodParams.size()][]);
 			this.postInitMethodParams = _postInitMethodParams.toArray(new Class[_postInitMethodParams.size()][]);
@@ -4139,8 +4139,28 @@ public final class RestContext extends BeanContext {
 	 * @param method The Java method to check.
 	 * @return The parameters defined on the Java method.
 	 */
-	public RestParam[] getRestParams(Method method) {
-		return callMethods.get(method.getName()).params;
+	public RestMethodParam[] getRestMethodParams(Method method) {
+		return callMethods.get(method.getName()).methodParams;
+	}
+
+	/**
+	 * Returns the parameters defined on the specified Java method.
+	 * 
+	 * @param method The Java method to check.
+	 * @return The parameters defined on the Java method.
+	 */
+	public RestMethodReturn getRestMethodReturn(Method method) {
+		return callMethods.get(method.getName()).methodReturn;
+	}
+
+	/**
+	 * Returns the parameters defined on the specified Java method.
+	 * 
+	 * @param method The Java method to check.
+	 * @return The parameters defined on the Java method.
+	 */
+	public RestMethodThrown[] getRestMethodThrowns(Method method) {
+		return callMethods.get(method.getName()).methodThrowns;
 	}
 
 	/**
@@ -4190,7 +4210,7 @@ public final class RestContext extends BeanContext {
 	}
 
 	/**
-	 * Finds the {@link RestParam} instances to handle resolving objects on the calls to the specified Java method.
+	 * Finds the {@link RestMethodParam} instances to handle resolving objects on the calls to the specified Java method.
 	 * 
 	 * @param method The Java method being called.
 	 * @param pathPattern The parsed URL path pattern.
@@ -4198,11 +4218,11 @@ public final class RestContext extends BeanContext {
 	 * @return The array of resolvers.
 	 * @throws ServletException If an annotation usage error was detected.
 	 */
-	protected RestParam[] findParams(Method method, UrlPathPattern pathPattern, boolean isPreOrPost) throws ServletException {
+	protected RestMethodParam[] findParams(Method method, UrlPathPattern pathPattern, boolean isPreOrPost) throws ServletException {
 
 		Type[] pt = method.getGenericParameterTypes();
 		Annotation[][] pa = method.getParameterAnnotations();
-		RestParam[] rp = new RestParam[pt.length];
+		RestMethodParam[] rp = new RestMethodParam[pt.length];
 		int attrIndex = 0;
 		PropertyStore ps = getPropertyStore();
 
@@ -4285,7 +4305,7 @@ public final class RestContext extends BeanContext {
 			preOrPost(resource, postCallMethods[i], postCallMethodParams[i], req, res);
 	}
 
-	private static void preOrPost(Object resource, Method m, RestParam[] mp, RestRequest req, RestResponse res) throws RestException {
+	private static void preOrPost(Object resource, Method m, RestMethodParam[] mp, RestRequest req, RestResponse res) throws RestException {
 		if (m != null) {
 			Object[] args = new Object[mp.length];
 			for (int i = 0; i < mp.length; i++) {
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
index c743db1..c9066be 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
@@ -1171,7 +1171,7 @@ public class RestContextBuilder extends BeanContextBuilder implements ServletCon
 	 * @return This object (for method chaining).
 	 */
 	@SuppressWarnings("unchecked")
-	public RestContextBuilder paramResolvers(Class<? extends RestParam>...values) {
+	public RestContextBuilder paramResolvers(Class<? extends RestMethodParam>...values) {
 		return addTo(REST_paramResolvers, values);
 	}
 
@@ -1189,7 +1189,7 @@ public class RestContextBuilder extends BeanContextBuilder implements ServletCon
 	 * @param values The values to add to this setting.
 	 * @return This object (for method chaining).
 	 */
-	public RestContextBuilder paramResolvers(RestParam...values) {
+	public RestContextBuilder paramResolvers(RestMethodParam...values) {
 		return addTo(REST_paramResolvers, values);
 	}
 
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
index f600a0f..41f21cf 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
@@ -44,7 +44,9 @@ import org.apache.juneau.utils.*;
 public class RestJavaMethod implements Comparable<RestJavaMethod>  {
 	private final String httpMethod;
 	private final UrlPathPattern pathPattern;
-	final RestParam[] params;
+	final RestMethodParam[] methodParams;
+	final RestMethodReturn methodReturn;
+	final RestMethodThrown[] methodThrowns;
 	private final RestGuard[] guards;
 	private final RestMatcher[] optionalMatchers;
 	private final RestMatcher[] requiredMatchers;
@@ -76,7 +78,9 @@ public class RestJavaMethod implements Comparable<RestJavaMethod>  {
 		this.method = method;
 		this.httpMethod = b.httpMethod;
 		this.pathPattern = b.pathPattern;
-		this.params = b.params;
+		this.methodParams = b.methodParams;
+		this.methodReturn = b.methodReturn;
+		this.methodThrowns = b.methodThrowns;
 		this.guards = b.guards;
 		this.optionalMatchers = b.optionalMatchers;
 		this.requiredMatchers = b.requiredMatchers;
@@ -102,7 +106,9 @@ public class RestJavaMethod implements Comparable<RestJavaMethod>  {
 	private static final class Builder  {
 		String httpMethod, defaultCharset;
 		UrlPathPattern pathPattern;
-		RestParam[] params;
+		RestMethodParam[] methodParams;
+		RestMethodReturn methodReturn;
+		RestMethodThrown[] methodThrowns;
 		RestGuard[] guards;
 		RestMatcher[] optionalMatchers, requiredMatchers;
 		RestConverter[] converters;
@@ -389,7 +395,13 @@ public class RestJavaMethod implements Comparable<RestJavaMethod>  {
 					? immutableList(MediaType.forStrings(resolveVars(vr, m.consumes()))) 
 					: parsers.getSupportedMediaTypes();
 					
-				params = context.findParams(method, pathPattern, false);
+				methodParams = context.findParams(method, pathPattern, false);
+				
+				methodReturn = new RestMethodReturn(method.getGenericReturnType());
+				
+				methodThrowns = new RestMethodThrown[method.getExceptionTypes().length];
+				for (int i = 0; i < methodThrowns.length; i++)
+					methodThrowns[i] = new RestMethodThrown(method.getExceptionTypes()[i]);
 
 				// Need this to access methods in anonymous inner classes.
 				setAccessible(method, true);
@@ -477,16 +489,16 @@ public class RestJavaMethod implements Comparable<RestJavaMethod>  {
 
 		context.preCall(req, res);
 
-		Object[] args = new Object[params.length];
-		for (int i = 0; i < params.length; i++) {
+		Object[] args = new Object[methodParams.length];
+		for (int i = 0; i < methodParams.length; i++) {
 			try {
-				args[i] = params[i].resolve(req, res);
+				args[i] = methodParams[i].resolve(req, res);
 			} catch (RestException e) {
 				throw e;
 			} catch (Exception e) {
 				throw new RestException(SC_BAD_REQUEST,
 					"Invalid data conversion.  Could not convert {0} ''{1}'' to type ''{2}'' on method ''{3}.{4}''.",
-					params[i].getParamType().name(), params[i].getName(), params[i].getType(), method.getDeclaringClass().getName(), method.getName()
+					methodParams[i].getParamType().name(), methodParams[i].getName(), methodParams[i].getType(), method.getDeclaringClass().getName(), method.getName()
 				).initCause(e);
 			}
 		}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParam.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodParam.java
similarity index 97%
rename from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParam.java
rename to juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodParam.java
index dad3b5c..f0b2bd4 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParam.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodParam.java
@@ -111,7 +111,7 @@ import org.apache.juneau.utils.*;
  * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.MethodParameters">Overview &gt; juneau-rest-server &gt; Java Method Parameters</a>
  * </ul>
  */
-public abstract class RestParam {
+public abstract class RestMethodParam {
 
 	final RestParamType paramType;
 	final String name;
@@ -127,7 +127,7 @@ public abstract class RestParam {
 	 * 	Can be <jk>null</jk> if parameter doesn't have a name (e.g. the request body).
 	 * @param type The object type to convert the parameter to.
 	 */
-	protected RestParam(RestParamType paramType, String name, Type type) {
+	protected RestMethodParam(RestParamType paramType, String name, Type type) {
 		this(paramType, name, type, ObjectMap.EMPTY_MAP);
 	}
 
@@ -141,7 +141,7 @@ public abstract class RestParam {
 	 * @param type The object type to convert the parameter to.
 	 * @param metaData Swagger metadata.
 	 */
-	protected RestParam(RestParamType paramType, String name, Type type, ObjectMap metaData) {
+	protected RestMethodParam(RestParamType paramType, String name, Type type, ObjectMap metaData) {
 		this.paramType = paramType;
 		this.name = name;
 		this.type = type;
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/IdConflictException.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodReturn.java
similarity index 54%
copy from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/IdConflictException.java
copy to juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodReturn.java
index a69bd25..ccdecc3 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/IdConflictException.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodReturn.java
@@ -10,25 +10,67 @@
 // * "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.examples.rest.petstore;
+package org.apache.juneau.rest;
+
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.lang.reflect.*;
 
 import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
 import org.apache.juneau.rest.annotation.*;
 
 /**
- * Exception thrown when trying to add an entry where the ID is already in use.
+ * Contains metadata about the return type on a REST Java method.
  */
-@SuppressWarnings("serial")
-@RestStatus(value=409, description="ID already in use")
-public class IdConflictException extends FormattedException {
+public class RestMethodReturn {
+	
+	private final Type type;
+	private final int code;
+	private final ObjectMap metaData;
+	
+	RestMethodReturn(Type type) {
+		this.type = type;
+		this.metaData = new ObjectMap();
+		
+		int code = 200;
+		if (type instanceof Class)
+		for (ResponseInfo ri : ReflectionUtils.findAnnotationsParentFirst(ResponseInfo.class, (Class<?>)type)) {
+			if (ri.code() != 0)
+				code = ri.code();
+			metaData.appendSkipEmpty("description", ri.description());
+			metaData.appendSkipEmpty("example", join(ri.example(), ""));
+			metaData.appendSkipEmpty("headers", join(ri.headers(), ""));
+			metaData.appendSkipEmpty("schema", join(ri.schema(), ""));
+		}
+		 
+		this.code = code;
+	}
+	
+	/**
+	 * Returns the return type of the Java method.
+	 * 
+	 * @return The return type of the Java method.
+	 */
+	public Type getType() {
+		return type;
+	}
 
 	/**
-	 * Constructor.
+	 * Returns the HTTP code code of the response.
+	 * 
+	 * @return The HTTP code code of the response.
+	 */
+	public int getCode() {
+		return code;
+	}
+	
+	/**
+	 * Returns the Swagger metadata associated with this return.
 	 * 
-	 * @param id The duplicate ID.
-	 * @param c The object type..
+	 * @return A map of return metadata, never <jk>null</jk>.
 	 */
-	public IdConflictException(Object id, Class<?> c) {
-		super("ID ''{0}'' already in use for type ''{1}''", id, c.getSimpleName());
+	public ObjectMap getMetaData() {
+		return metaData;
 	}
 }
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/IdConflictException.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodThrown.java
similarity index 55%
copy from juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/IdConflictException.java
copy to juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodThrown.java
index a69bd25..ff9e511 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/petstore/IdConflictException.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodThrown.java
@@ -10,25 +10,66 @@
 // * "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.examples.rest.petstore;
+package org.apache.juneau.rest;
+
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.lang.reflect.*;
 
 import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
 import org.apache.juneau.rest.annotation.*;
 
 /**
- * Exception thrown when trying to add an entry where the ID is already in use.
+ * Contains metadata about a throwable on a REST Java method.
  */
-@SuppressWarnings("serial")
-@RestStatus(value=409, description="ID already in use")
-public class IdConflictException extends FormattedException {
+public class RestMethodThrown {
+	
+	final Class<?> type;
+	final int code;
+	final ObjectMap metaData;
+	
+	RestMethodThrown(Class<?> type) {
+		this.type = type;
+		this.metaData = new ObjectMap();
+		
+		int code = 500;
+		for (ResponseInfo ri : ReflectionUtils.findAnnotationsParentFirst(ResponseInfo.class, type)) {
+			if (ri.code() != 0)
+				code = ri.code();
+			metaData.appendSkipEmpty("description", ri.description());
+			metaData.appendSkipEmpty("example", join(ri.example(), ""));
+			metaData.appendSkipEmpty("headers", join(ri.headers(), ""));
+			metaData.appendSkipEmpty("schema", join(ri.schema(), ""));
+		}
+		
+		this.code = code;
+	}
+	
+	/**
+	 * Returns the return type of the Java method.
+	 * 
+	 * @return The return type of the Java method.
+	 */
+	public Type getType() {
+		return type;
+	}
 
 	/**
-	 * Constructor.
+	 * Returns the HTTP status code of the response.
+	 * 
+	 * @return The HTTP status code of the response.
+	 */
+	public int getCode() {
+		return code;
+	}
+	
+	/**
+	 * Returns the Swagger metadata associated with this return.
 	 * 
-	 * @param id The duplicate ID.
-	 * @param c The object type..
+	 * @return A map of return metadata, never <jk>null</jk>.
 	 */
-	public IdConflictException(Object id, Class<?> c) {
-		super("ID ''{0}'' already in use for type ''{1}''", id, c.getSimpleName());
+	public ObjectMap getMetaData() {
+		return metaData;
 	}
 }
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 f59cfb8..dafc52a 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
@@ -50,10 +50,10 @@ class RestParamDefaults {
 	/**
 	 * Standard set of method parameter resolvers.
 	 */
-	static final Map<Class<?>,RestParam> STANDARD_RESOLVERS;
+	static final Map<Class<?>,RestMethodParam> STANDARD_RESOLVERS;
 
 	static {
-		Map<Class<?>,RestParam> m = new HashMap<>();
+		Map<Class<?>,RestMethodParam> m = new HashMap<>();
 
 		@SuppressWarnings("rawtypes")
 		Class[] r = new Class[] {
@@ -123,7 +123,7 @@ class RestParamDefaults {
 
 		for (Class<?> c : r) {
 			try {
-				RestParam mpr = (RestParam)c.newInstance();
+				RestMethodParam mpr = (RestMethodParam)c.newInstance();
 				m.put(mpr.forClass(), mpr);
 			} catch (Exception e) {
 				e.printStackTrace();
@@ -137,49 +137,49 @@ class RestParamDefaults {
 	// Request / Response retrievers
 	//-------------------------------------------------------------------------------------------------------------------
 
-	static final class HttpServletRequestObject extends RestParam {
+	static final class HttpServletRequestObject extends RestMethodParam {
 
 		protected HttpServletRequestObject() {
 			super(OTHER, null, HttpServletRequest.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) {
 			return req;
 		}
 	}
 
-	static final class HttpServletResponseObject extends RestParam {
+	static final class HttpServletResponseObject extends RestMethodParam {
 
 		protected HttpServletResponseObject() {
 			super(OTHER, null, HttpServletResponse.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) {
 			return res;
 		}
 	}
 
-	static final class RestRequestObject extends RestParam {
+	static final class RestRequestObject extends RestMethodParam {
 
 		protected RestRequestObject() {
 			super(OTHER, null, RestRequest.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) {
 			return req;
 		}
 	}
 
-	static final class RestResponseObject extends RestParam {
+	static final class RestResponseObject extends RestMethodParam {
 
 		protected RestResponseObject() {
 			super(OTHER, null, RestResponse.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) {
 			return res;
 		}
@@ -189,31 +189,31 @@ class RestParamDefaults {
 	// Header retrievers
 	//-------------------------------------------------------------------------------------------------------------------
 
-	static final class AcceptHeader extends RestParam {
+	static final class AcceptHeader extends RestMethodParam {
 
 		protected AcceptHeader() {
 			super(HEADER, "Accept-Header", Accept.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) {
 			return req.getHeaders().getAccept();
 		}
 	}
 
-	static final class AcceptCharsetHeader extends RestParam {
+	static final class AcceptCharsetHeader extends RestMethodParam {
 
 		protected AcceptCharsetHeader() {
 			super(HEADER, "Accept-Charset", AcceptCharset.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public AcceptCharset resolve(RestRequest req, RestResponse res) {
 			return req.getHeaders().getAcceptCharset();
 		}
 	}
 
-	static final class AcceptEncodingHeader extends RestParam {
+	static final class AcceptEncodingHeader extends RestMethodParam {
 
 		protected AcceptEncodingHeader() {
 			super(HEADER, "Accept-Encoding", AcceptEncoding.class);
@@ -225,7 +225,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class AcceptLanguageHeader extends RestParam {
+	static final class AcceptLanguageHeader extends RestMethodParam {
 
 		protected AcceptLanguageHeader() {
 			super(HEADER, "Accept-Language", AcceptLanguage.class);
@@ -237,7 +237,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class AuthorizationHeader extends RestParam {
+	static final class AuthorizationHeader extends RestMethodParam {
 
 		protected AuthorizationHeader() {
 			super(HEADER, "Authorization", Authorization.class);
@@ -249,7 +249,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class CacheControlHeader extends RestParam {
+	static final class CacheControlHeader extends RestMethodParam {
 
 		protected CacheControlHeader() {
 			super(HEADER, "Cache-Control", CacheControl.class);
@@ -261,7 +261,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class ConnectionHeader extends RestParam {
+	static final class ConnectionHeader extends RestMethodParam {
 
 		protected ConnectionHeader() {
 			super(HEADER, "Connection", Connection.class);
@@ -273,7 +273,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class ContentLengthHeader extends RestParam {
+	static final class ContentLengthHeader extends RestMethodParam {
 
 		protected ContentLengthHeader() {
 			super(HEADER, "Content-Length", ContentLength.class);
@@ -285,7 +285,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class ContentTypeHeader extends RestParam {
+	static final class ContentTypeHeader extends RestMethodParam {
 
 		protected ContentTypeHeader() {
 			super(HEADER, "Content-Type", ContentType.class);
@@ -297,7 +297,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class DateHeader extends RestParam {
+	static final class DateHeader extends RestMethodParam {
 
 		protected DateHeader() {
 			super(HEADER, "Date", Date.class);
@@ -309,7 +309,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class ExpectHeader extends RestParam {
+	static final class ExpectHeader extends RestMethodParam {
 
 		protected ExpectHeader() {
 			super(HEADER, "Expect", Expect.class);
@@ -321,7 +321,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class FromHeader extends RestParam {
+	static final class FromHeader extends RestMethodParam {
 
 		protected FromHeader() {
 			super(HEADER, "From", From.class);
@@ -333,7 +333,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class HostHeader extends RestParam {
+	static final class HostHeader extends RestMethodParam {
 
 		protected HostHeader() {
 			super(HEADER, "Host", Host.class);
@@ -345,7 +345,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class IfMatchHeader extends RestParam {
+	static final class IfMatchHeader extends RestMethodParam {
 
 		protected IfMatchHeader() {
 			super(HEADER, "If-Match", IfMatch.class);
@@ -357,7 +357,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class IfModifiedSinceHeader extends RestParam {
+	static final class IfModifiedSinceHeader extends RestMethodParam {
 
 		protected IfModifiedSinceHeader() {
 			super(HEADER, "If-Modified-Since", IfModifiedSince.class);
@@ -369,7 +369,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class IfNoneMatchHeader extends RestParam {
+	static final class IfNoneMatchHeader extends RestMethodParam {
 
 		protected IfNoneMatchHeader() {
 			super(HEADER, "If-None-Match", IfNoneMatch.class);
@@ -381,7 +381,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class IfRangeHeader extends RestParam {
+	static final class IfRangeHeader extends RestMethodParam {
 
 		protected IfRangeHeader() {
 			super(HEADER, "If-Range", IfRange.class);
@@ -393,7 +393,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class IfUnmodifiedSinceHeader extends RestParam {
+	static final class IfUnmodifiedSinceHeader extends RestMethodParam {
 
 		protected IfUnmodifiedSinceHeader() {
 			super(HEADER, "If-Unmodified-Since", IfUnmodifiedSince.class);
@@ -405,7 +405,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class MaxForwardsHeader extends RestParam {
+	static final class MaxForwardsHeader extends RestMethodParam {
 
 		protected MaxForwardsHeader() {
 			super(HEADER, "Max-Forwards", MaxForwards.class);
@@ -417,7 +417,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class PragmaHeader extends RestParam {
+	static final class PragmaHeader extends RestMethodParam {
 
 		protected PragmaHeader() {
 			super(HEADER, "Pragma", Pragma.class);
@@ -429,7 +429,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class ProxyAuthorizationHeader extends RestParam {
+	static final class ProxyAuthorizationHeader extends RestMethodParam {
 
 		protected ProxyAuthorizationHeader() {
 			super(HEADER, "Proxy-Authorization", ProxyAuthorization.class);
@@ -441,7 +441,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class RangeHeader extends RestParam {
+	static final class RangeHeader extends RestMethodParam {
 
 		protected RangeHeader() {
 			super(HEADER, "Range", Range.class);
@@ -453,7 +453,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class RefererHeader extends RestParam {
+	static final class RefererHeader extends RestMethodParam {
 
 		protected RefererHeader() {
 			super(HEADER, "Referer", Referer.class);
@@ -465,7 +465,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class TEHeader extends RestParam {
+	static final class TEHeader extends RestMethodParam {
 
 		protected TEHeader() {
 			super(HEADER, "TE", TE.class);
@@ -477,7 +477,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class UserAgentHeader extends RestParam {
+	static final class UserAgentHeader extends RestMethodParam {
 
 		protected UserAgentHeader() {
 			super(HEADER, "User-Agent", UserAgent.class);
@@ -489,7 +489,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class UpgradeHeader extends RestParam {
+	static final class UpgradeHeader extends RestMethodParam {
 
 		protected UpgradeHeader() {
 			super(HEADER, "Upgrade", Upgrade.class);
@@ -501,7 +501,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class ViaHeader extends RestParam {
+	static final class ViaHeader extends RestMethodParam {
 
 		protected ViaHeader() {
 			super(HEADER, "Via", Via.class);
@@ -513,7 +513,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class WarningHeader extends RestParam {
+	static final class WarningHeader extends RestMethodParam {
 
 		protected WarningHeader() {
 			super(HEADER, "Warning", Warning.class);
@@ -525,7 +525,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class TimeZoneHeader extends RestParam {
+	static final class TimeZoneHeader extends RestMethodParam {
 
 		protected TimeZoneHeader() {
 			super(HEADER, "Time-Zone", TimeZone.class);
@@ -541,13 +541,13 @@ class RestParamDefaults {
 	// Annotated retrievers
 	//-------------------------------------------------------------------------------------------------------------------
 
-	static final class PathParameterObject extends RestParam {
+	static final class PathParameterObject extends RestMethodParam {
 
 		protected PathParameterObject(String name, Path a, Type type) {
 			super(PATH, name, type, getMetaData(a));
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getPathMatch().get(name, type);
 		}
@@ -575,13 +575,13 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class BodyObject extends RestParam {
+	static final class BodyObject extends RestMethodParam {
 
 		protected BodyObject(Method method, Body a, Type type) {
 			super(BODY, null, type, getMetaData(a));
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getBody().asType(type);
 		}
@@ -616,7 +616,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class HeaderObject extends RestParam {
+	static final class HeaderObject extends RestMethodParam {
 		private final HttpPartParser partParser;
 
 		protected HeaderObject(Method method, Header a, Type type, PropertyStore ps) {
@@ -624,7 +624,7 @@ class RestParamDefaults {
 			this.partParser = a.parser() == HttpPartParser.Null.class ? null : ClassUtils.newInstance(HttpPartParser.class, a.parser(), true, ps);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getHeaders().get(partParser, name, type);
 		}
@@ -659,7 +659,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class MethodObject extends RestParam {
+	static final class MethodObject extends RestMethodParam {
 
 		protected MethodObject(Method method, Type type) throws ServletException {
 			super(OTHER, null, null);
@@ -667,13 +667,13 @@ class RestParamDefaults {
 				throw new RestServletException("Use of @Method annotation on parameter that is not a String on method ''{0}''", method);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getMethod();
 		}
 	}
 
-	static final class FormDataObject extends RestParam {
+	static final class FormDataObject extends RestMethodParam {
 		private final boolean multiPart;
 		private final HttpPartParser partParser;
 
@@ -685,7 +685,7 @@ class RestParamDefaults {
 			this.partParser = a.parser() == HttpPartParser.Null.class ? null : ClassUtils.newInstance(HttpPartParser.class, a.parser(), true, ps);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			if (multiPart)
 				return req.getFormData().getAll(partParser, name, type);
@@ -722,7 +722,7 @@ class RestParamDefaults {
 		}
 	}
 
-	static final class QueryObject extends RestParam {
+	static final class QueryObject extends RestMethodParam {
 		private final boolean multiPart;
 		private final HttpPartParser partParser;
 
@@ -734,7 +734,7 @@ class RestParamDefaults {
 			this.partParser = a.parser() == HttpPartParser.Null.class ? null : ClassUtils.newInstance(HttpPartParser.class, a.parser(), true, ps);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			if (multiPart)
 				return req.getQuery().getAll(partParser, name, type);
@@ -772,7 +772,7 @@ class RestParamDefaults {
 
 	}
 
-	static final class HasFormDataObject extends RestParam {
+	static final class HasFormDataObject extends RestMethodParam {
 
 		protected HasFormDataObject(Method method, HasFormData a, Type type) throws ServletException {
 			super(FORM_DATA, firstNonEmpty(a.name(), a.value()), type);
@@ -780,14 +780,14 @@ class RestParamDefaults {
 				throw new RestServletException("Use of @HasForm annotation on parameter that is not a boolean on method ''{0}''", method);
 	}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			BeanSession bs = req.getBeanSession();
 			return bs.convertToType(req.getFormData().containsKey(name), bs.getClassMeta(type));
 		}
 	}
 
-	static final class HasQueryObject extends RestParam {
+	static final class HasQueryObject extends RestMethodParam {
 
 		protected HasQueryObject(Method method, HasQuery a, Type type) throws ServletException {
 			super(QUERY, firstNonEmpty(a.name(), a.value()), type);
@@ -795,14 +795,14 @@ class RestParamDefaults {
 				throw new RestServletException("Use of @HasQuery annotation on parameter that is not a boolean on method ''{0}''", method);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			BeanSession bs = req.getBeanSession();
 			return bs.convertToType(req.getQuery().containsKey(name), bs.getClassMeta(type));
 		}
 	}
 
-	static final class PathRemainderObject extends RestParam {
+	static final class PathRemainderObject extends RestMethodParam {
 
 		protected PathRemainderObject(Method method, Type type) throws ServletException {
 			super(OTHER, null, null);
@@ -810,19 +810,19 @@ class RestParamDefaults {
 				throw new RestServletException("Use of @PathRemainder annotation on parameter that is not a String on method ''{0}''", method);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getPathMatch().getRemainder();
 		}
 	}
 
-	static final class RestRequestPropertiesObject extends RestParam {
+	static final class RestRequestPropertiesObject extends RestMethodParam {
 
 		protected RestRequestPropertiesObject() {
 			super(OTHER, null, RequestProperties.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public RequestProperties resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getProperties();
 		}
@@ -832,265 +832,265 @@ class RestParamDefaults {
 	// Other retrievers
 	//-------------------------------------------------------------------------------------------------------------------
 
-	static final class ResourceBundleObject extends RestParam {
+	static final class ResourceBundleObject extends RestMethodParam {
 
 		protected ResourceBundleObject() {
 			super(OTHER, null, ResourceBundle.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getMessageBundle();
 		}
 	}
 
-	static final class MessageBundleObject extends RestParam {
+	static final class MessageBundleObject extends RestMethodParam {
 
 		protected MessageBundleObject() {
 			super(OTHER, null, MessageBundle.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getMessageBundle();
 		}
 	}
 
-	static final class InputStreamObject extends RestParam {
+	static final class InputStreamObject extends RestMethodParam {
 
 		protected InputStreamObject() {
 			super(OTHER, null, InputStream.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getInputStream();
 		}
 	}
 
-	static final class ServletInputStreamObject extends RestParam {
+	static final class ServletInputStreamObject extends RestMethodParam {
 
 		protected ServletInputStreamObject() {
 			super(OTHER, null, ServletInputStream.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getInputStream();
 		}
 	}
 
-	static final class ReaderObject extends RestParam {
+	static final class ReaderObject extends RestMethodParam {
 
 		protected ReaderObject() {
 			super(OTHER, null, Reader.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getReader();
 		}
 	}
 
-	static final class OutputStreamObject extends RestParam {
+	static final class OutputStreamObject extends RestMethodParam {
 
 		protected OutputStreamObject() {
 			super(OTHER, null, OutputStream.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return res.getOutputStream();
 		}
 	}
 
-	static final class ServletOutputStreamObject extends RestParam {
+	static final class ServletOutputStreamObject extends RestMethodParam {
 
 		protected ServletOutputStreamObject() {
 			super(OTHER, null, ServletOutputStream.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return res.getOutputStream();
 		}
 	}
 
-	static final class WriterObject extends RestParam {
+	static final class WriterObject extends RestMethodParam {
 
 		protected WriterObject() {
 			super(OTHER, null, Writer.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return res.getWriter();
 		}
 	}
 
-	static final class RequestHeadersObject extends RestParam {
+	static final class RequestHeadersObject extends RestMethodParam {
 
 		protected RequestHeadersObject() {
 			super(OTHER, null, RequestHeaders.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getHeaders();
 		}
 	}
 
-	static final class RequestQueryObject extends RestParam {
+	static final class RequestQueryObject extends RestMethodParam {
 
 		protected RequestQueryObject() {
 			super(OTHER, null, RequestQuery.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getQuery();
 		}
 	}
 
-	static final class RequestFormDataObject extends RestParam {
+	static final class RequestFormDataObject extends RestMethodParam {
 
 		protected RequestFormDataObject() {
 			super(OTHER, null, RequestFormData.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getFormData();
 		}
 	}
 
-	static final class HttpMethodObject extends RestParam {
+	static final class HttpMethodObject extends RestMethodParam {
 
 		protected HttpMethodObject() {
 			super(OTHER, null, HttpMethod.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getHttpMethod();
 		}
 	}
 
-	static final class RestLoggerObject extends RestParam {
+	static final class RestLoggerObject extends RestMethodParam {
 
 		protected RestLoggerObject() {
 			super(OTHER, null, RestLogger.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public RestLogger resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getContext().getLogger();
 		}
 	}
 
-	static final class RestContextObject extends RestParam {
+	static final class RestContextObject extends RestMethodParam {
 
 		protected RestContextObject() {
 			super(OTHER, null, RestContext.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getContext();
 		}
 	}
 
-	static final class ParserObject extends RestParam {
+	static final class ParserObject extends RestMethodParam {
 
 		protected ParserObject() {
 			super(OTHER, null, Parser.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getBody().getParser();
 		}
 	}
 
-	static final class LocaleObject extends RestParam {
+	static final class LocaleObject extends RestMethodParam {
 
 		protected LocaleObject() {
 			super(OTHER, null, Locale.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getLocale();
 		}
 	}
 
-	static final class SwaggerObject extends RestParam {
+	static final class SwaggerObject extends RestMethodParam {
 
 		protected SwaggerObject() {
 			super(OTHER, null, Swagger.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getSwagger();
 		}
 	}
 
-	static final class RequestPathMatchObject extends RestParam {
+	static final class RequestPathMatchObject extends RestMethodParam {
 
 		protected RequestPathMatchObject() {
 			super(OTHER, null, RequestPathMatch.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getPathMatch();
 		}
 	}
 
-	static final class RequestBodyObject extends RestParam {
+	static final class RequestBodyObject extends RestMethodParam {
 
 		protected RequestBodyObject() {
 			super(BODY, null, RequestBody.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getBody();
 		}
 	}
 
-	static final class ConfigObject extends RestParam {
+	static final class ConfigObject extends RestMethodParam {
 
 		protected ConfigObject() {
 			super(OTHER, null, Config.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getConfig();
 		}
 	}
 
-	static final class UriContextObject extends RestParam {
+	static final class UriContextObject extends RestMethodParam {
 
 		protected UriContextObject() {
 			super(OTHER, null, UriContext.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getUriContext();
 		}
 	}
 
-	static final class UriResolverObject extends RestParam {
+	static final class UriResolverObject extends RestMethodParam {
 
 		protected UriResolverObject() {
 			super(OTHER, null, UriResolver.class);
 		}
 
-		@Override /* RestParam */
+		@Override /* RestMethodParam */
 		public Object resolve(RestRequest req, RestResponse res) throws Exception {
 			return req.getUriResolver();
 		}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestStatus.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResponseInfo.java
similarity index 73%
rename from juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestStatus.java
rename to juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResponseInfo.java
index 2ac1235..3c300b9 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestStatus.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResponseInfo.java
@@ -17,27 +17,49 @@ import static java.lang.annotation.RetentionPolicy.*;
 
 import java.lang.annotation.*;
 
-import javax.servlet.http.*;
-
 /**
- * Annotation that can be applied to exceptions that identify the HTTP status they trigger and a description about the exception.
+ * Annotation that can be applied to exceptions and return types that identify the HTTP status they trigger and a description about the exception.
  */
 @Documented
 @Target(TYPE)
 @Retention(RUNTIME)
 @Inherited
-public @interface RestStatus {
+public @interface ResponseInfo {
 	
 	/**
 	 * The HTTP status of the response.
 	 */
-	int value() default HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
+	int code() default 0;
 	
 	/**
-	 * Optional description.
+	 * Description.
 	 * 
 	 * <p>
-	 * Used when generating Swagger documentation.
+	 * Format is plain text.
 	 */
 	String description() default "";
+
+	/**
+	 * Schema information.
+	 * 
+	 * <p>
+	 * Format is a JSON object consisting of a Swagger SchemaInfo object.
+	 */
+	String[] schema() default {};
+	
+	/**
+	 * Header information.
+	 * 
+	 * <p>
+	 * Format is a JSON array consisting of Swagger HeaderInfo objects.
+	 */
+	String[] headers() default {};
+	
+	/**
+	 * Example.
+	 * 
+	 * <p>
+	 * Format is a JSON primitive, array, or object.
+	 */
+	String[] example() default {};
 }
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
index f85a549..c2b3470 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
@@ -523,7 +523,7 @@ public @interface RestResource {
 	 * 	<li class='jf'>{@link RestContext#REST_paramResolvers}
 	 * </ul>
 	 */
-	Class<? extends RestParam>[] paramResolvers() default {};
+	Class<? extends RestMethodParam>[] paramResolvers() default {};
 
 	/**
 	 * Parser listener.

-- 
To stop receiving notification emails like this one, please contact
jamesbognar@apache.org.

Mime
View raw message