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 <jamesbog...@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:'j...@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:'d...@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
jamesbog...@apache.org.

Reply via email to