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

[juneau] branch master updated: Improvements to @Schema support.

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 a186a15  Improvements to @Schema support.
a186a15 is described below

commit a186a1592431137f34db9b4f443de1323a023b14
Author: JamesBognar <ja...@apache.org>
AuthorDate: Sat Sep 29 14:44:21 2018 -0400

    Improvements to @Schema support.
---
 .../httppart/HttpPartSchemaTest_FormData.java      |   1 +
 .../juneau/httppart/HttpPartSchemaTest_Header.java |   1 +
 .../juneau/httppart/HttpPartSchemaTest_Path.java   |   1 +
 .../juneau/httppart/HttpPartSchemaTest_Query.java  |   1 +
 .../HttpPartSchemaTest_ResponseHeader.java         |   1 +
 .../juneau/jsonschema/JsonSchemaGeneratorTest.java |  14 +-
 .../org/apache/juneau/utils/ClassUtilsTest.java    |   8 +-
 .../src/main/java/org/apache/juneau/BeanMeta.java  |   4 +-
 .../java/org/apache/juneau/BeanPropertyMeta.java   |  18 +-
 .../org/apache/juneau/http/HeaderStringArray.java  |   1 +
 .../apache/juneau/http/annotation/FormData.java    |   1 +
 .../org/apache/juneau/http/annotation/Header.java  |   1 +
 .../org/apache/juneau/http/annotation/Path.java    |   1 +
 .../org/apache/juneau/http/annotation/Query.java   |   1 +
 .../juneau/http/annotation/ResponseHeader.java     |   1 +
 .../org/apache/juneau/http/annotation/Tag.java     |   2 +
 .../org/apache/juneau/internal/ClassUtils.java     | 370 ++++++++++++---------
 .../jsonschema/JsonSchemaBeanPropertyMeta.java     |  83 ++---
 .../juneau/jsonschema/JsonSchemaClassMeta.java     |  68 +---
 .../jsonschema/JsonSchemaGeneratorSession.java     |  17 +-
 .../org/apache/juneau/jsonschema/SchemaUtils.java  | 190 +++++++++++
 .../annotation/ExternalDocs.java                   |   2 +-
 .../{http => jsonschema}/annotation/Items.java     |   2 +-
 .../{http => jsonschema}/annotation/SubItems.java  |   2 +-
 .../juneau/examples/rest/AtomFeedResource.java     |   1 +
 .../examples/rest/CodeFormatterResource.java       |   1 +
 .../examples/rest/DockerRegistryResource.java      |   1 +
 .../juneau/examples/rest/JsonSchemaResource.java   |   1 +
 .../examples/rest/MethodExampleResource.java       |   1 +
 .../juneau/examples/rest/PhotosResource.java       |   1 +
 .../examples/rest/PredefinedLabelsResource.java    |   1 +
 .../juneau/examples/rest/RequestEchoResource.java  |   1 +
 .../rest/SampleRemoteInterfaceServlet.java         |   1 +
 .../juneau/examples/rest/SqlQueryResource.java     |   1 +
 .../examples/rest/SystemPropertiesResource.java    |   1 +
 .../juneau/examples/rest/TempDirResource.java      |   1 +
 .../examples/rest/UrlEncodedFormResource.java      |   1 +
 .../rest/addressbook/AddressBookResource.java      |   1 +
 .../examples/rest/petstore/PetStoreResource.java   |   1 +
 .../rest/client/remote/FormDataAnnotationTest.java |   1 +
 .../rest/client/remote/HeaderAnnotationTest.java   |   1 +
 .../rest/client/remote/PathAnnotationTest.java     |   1 +
 .../rest/client/remote/QueryAnnotationTest.java    |   1 +
 .../java/org/apache/juneau/rest/RestContext.java   |   4 +-
 .../org/apache/juneau/rest/SwaggerGenerator.java   |   2 +-
 .../juneau/rest/annotation/MethodSwagger.java      |   2 +-
 .../juneau/rest/annotation/ResourceSwagger.java    |   1 +
 .../rest/annotation/AnnotationInheritanceTest.java |  48 +++
 .../rest/annotation/QueryAnnotationTest.java       |   2 +-
 49 files changed, 540 insertions(+), 329 deletions(-)

diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_FormData.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_FormData.java
index a5cce07..f829e56 100644
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_FormData.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_FormData.java
@@ -19,6 +19,7 @@ import static org.apache.juneau.internal.StringUtils.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
 import org.junit.runners.*;
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Header.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Header.java
index 1739fcb..d4333bb 100644
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Header.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Header.java
@@ -19,6 +19,7 @@ import static org.apache.juneau.internal.StringUtils.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
 import org.junit.runners.*;
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Path.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Path.java
index 1fe94ca..0d05063 100644
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Path.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Path.java
@@ -19,6 +19,7 @@ import static org.apache.juneau.internal.StringUtils.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
 import org.junit.runners.*;
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Query.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Query.java
index 373daaf..7424e8d 100644
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Query.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Query.java
@@ -19,6 +19,7 @@ import static org.apache.juneau.internal.StringUtils.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
 import org.junit.runners.*;
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_ResponseHeader.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_ResponseHeader.java
index 5dc0aef..d31cb41 100644
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_ResponseHeader.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_ResponseHeader.java
@@ -19,6 +19,7 @@ import static org.junit.Assert.assertEquals;
 
 import org.apache.juneau.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
 import org.junit.runners.*;
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/jsonschema/JsonSchemaGeneratorTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/jsonschema/JsonSchemaGeneratorTest.java
index 9ccf29d..400841e 100755
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/jsonschema/JsonSchemaGeneratorTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/jsonschema/JsonSchemaGeneratorTest.java
@@ -1134,7 +1134,7 @@ public class JsonSchemaGeneratorTest {
 	@Test
 	public void jsonSchema_onclass() throws Exception {
 		JsonSchemaGeneratorSession s = JsonSchemaGenerator.DEFAULT.builder().build().createSession();
-		assertObjectEquals("{type:'foo',format:'bar',properties:{f1:{type:'integer',format:'int32'}},description:'baz','x-example':{f1:123}}", s.getSchema(A1.class));
+		assertObjectEquals("{description:'baz',format:'bar',type:'foo','x-example':'{f1:123}',properties:{f1:{type:'integer',format:'int32'}}}", s.getSchema(A1.class));
 	}
 
 	@Schema(type="foo",format="bar",description="baz",example="{f1:123}")
@@ -1145,7 +1145,7 @@ public class JsonSchemaGeneratorTest {
 	@Test
 	public void jsonSchema_onbeanfield() throws Exception {
 		JsonSchemaGeneratorSession s = JsonSchemaGenerator.DEFAULT.builder().build().createSession();
-		assertObjectEquals("{type:'object',properties:{f1:{type:'foo',format:'bar',description:'baz','x-example':123}}}", s.getSchema(A2.class));
+		assertObjectEquals("{type:'object',properties:{f1:{description:'baz',format:'bar',type:'foo','x-example':'123'}}}", s.getSchema(A2.class));
 	}
 
 	public static class A2 {
@@ -1156,7 +1156,7 @@ public class JsonSchemaGeneratorTest {
 	@Test
 	public void jsonSchema_onbeangetter() throws Exception {
 		JsonSchemaGeneratorSession s = JsonSchemaGenerator.DEFAULT.builder().build().createSession();
-		assertObjectEquals("{type:'object',properties:{f1:{type:'foo',format:'bar',description:'baz','x-example':123}}}", s.getSchema(A3.class));
+		assertObjectEquals("{type:'object',properties:{f1:{description:'baz',format:'bar',type:'foo','x-example':'123'}}}", s.getSchema(A3.class));
 	}
 
 	public static class A3 {
@@ -1169,7 +1169,7 @@ public class JsonSchemaGeneratorTest {
 
 	public void jsonSchema_onbeansetter() throws Exception {
 		JsonSchemaGeneratorSession s = JsonSchemaGenerator.DEFAULT.builder().build().createSession();
-		assertObjectEquals("{type:'object',properties:{f1:{type:'foo',format:'bar',description:'baz','x-example':123}}}", s.getSchema(A4.class));
+		assertObjectEquals("{type:'object',properties:{f1:{description:'baz',format:'bar',type:'foo','x-example':'123'}}}", s.getSchema(A4.class));
 	}
 
 	public static class A4 {
@@ -1190,9 +1190,9 @@ public class JsonSchemaGeneratorTest {
 		JsonSchemaGeneratorSession s = JsonSchemaGenerator.DEFAULT.builder()
 			.pojoSwaps(SwapWithAnnotation.class)
 			.build().createSession();
-		assertObjectEquals("{type:'foo',format:'bar',description:'baz','x-example':123}", s.getSchema(SimpleBean.class));
-		assertObjectEquals("{type:'array',items:{type:'foo',format:'bar',description:'baz','x-example':123}}", s.getSchema(BeanList.class));
-		assertObjectEquals("{type:'array',items:{type:'array',items:{type:'foo',format:'bar',description:'baz','x-example':123}}}", s.getSchema(SimpleBean[][].class));
+		assertObjectEquals("{description:'baz',format:'bar',type:'foo','x-example':'123'}", s.getSchema(SimpleBean.class));
+		assertObjectEquals("{type:'array',items:{description:'baz',format:'bar',type:'foo','x-example':'123'}}", s.getSchema(BeanList.class));
+		assertObjectEquals("{type:'array',items:{type:'array',items:{description:'baz',format:'bar',type:'foo','x-example':'123'}}}", s.getSchema(SimpleBean[][].class));
 	}
 
 	@Schema(type="foo",format="bar",description="baz",example="123")
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/ClassUtilsTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/ClassUtilsTest.java
index 840a0b1..ef2f637 100755
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/ClassUtilsTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/utils/ClassUtilsTest.java
@@ -164,10 +164,10 @@ public class ClassUtilsTest {
 	//====================================================================================================
 	@Test
 	public void getMethodAnnotations() throws Exception {
-		assertEquals("a1", getMethodAnnotation(TestAnnotation.class, CI3.class.getMethod("a1")).value());
-		assertEquals("a2b", getMethodAnnotation(TestAnnotation.class, CI3.class.getMethod("a2")).value());
-		assertEquals("a3", getMethodAnnotation(TestAnnotation.class, CI3.class.getMethod("a3", CharSequence.class)).value());
-		assertEquals("a4", getMethodAnnotation(TestAnnotation.class, CI3.class.getMethod("a4")).value());
+		assertEquals("a1", getAnnotation(TestAnnotation.class, CI3.class.getMethod("a1")).value());
+		assertEquals("a2b", getAnnotation(TestAnnotation.class, CI3.class.getMethod("a2")).value());
+		assertEquals("a3", getAnnotation(TestAnnotation.class, CI3.class.getMethod("a3", CharSequence.class)).value());
+		assertEquals("a4", getAnnotation(TestAnnotation.class, CI3.class.getMethod("a4")).value());
 	}
 
 	public static interface CI1 {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
index f7c63ba..267cf69 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
@@ -602,11 +602,11 @@ public class BeanMeta<T> {
 				if (m.isBridge())   // This eliminates methods with covariant return types from parent classes on child classes.
 					continue;
 
-				BeanIgnore bi = getMethodAnnotation(BeanIgnore.class, c, m);
+				BeanIgnore bi = getAnnotation(BeanIgnore.class, m);
 				if (bi != null)
 					continue;
 
-				BeanProperty bp = getMethodAnnotation(BeanProperty.class, c, m);
+				BeanProperty bp = getAnnotation(BeanProperty.class, m);
 				if (! (v.isVisible(m) || bp != null))
 					continue;
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
index a9ed6eb..c43248e 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
@@ -193,7 +193,7 @@ public final class BeanPropertyMeta {
 			}
 
 			if (getter != null) {
-				BeanProperty p = getMethodAnnotation(BeanProperty.class, getter);
+				BeanProperty p = getAnnotation(BeanProperty.class, getter);
 				if (rawTypeMeta == null)
 					rawTypeMeta = f.resolveClassMeta(p, getter.getGenericReturnType(), typeVarImpls);
 				isUri |= (rawTypeMeta.isUri() || getter.isAnnotationPresent(org.apache.juneau.annotation.URI.class));
@@ -209,7 +209,7 @@ public final class BeanPropertyMeta {
 			}
 
 			if (setter != null) {
-				BeanProperty p = getMethodAnnotation(BeanProperty.class, setter);
+				BeanProperty p = getAnnotation(BeanProperty.class, setter);
 				if (rawTypeMeta == null)
 					rawTypeMeta = f.resolveClassMeta(p, setter.getGenericParameterTypes()[0], typeVarImpls);
 				isUri |= (rawTypeMeta.isUri() || setter.isAnnotationPresent(org.apache.juneau.annotation.URI.class));
@@ -1063,15 +1063,15 @@ public final class BeanPropertyMeta {
 			appendAnnotations(a, field.getType(), l);
 		}
 		if (getter != null) {
-			addIfNotNull(l, getMethodAnnotation(a, getter));
+			addIfNotNull(l, getAnnotation(a, getter));
 			appendAnnotations(a, getter.getReturnType(), l);
 		}
 		if (setter != null) {
-			addIfNotNull(l, getMethodAnnotation(a, setter));
+			addIfNotNull(l, getAnnotation(a, setter));
 			appendAnnotations(a, setter.getReturnType(), l);
 		}
 		if (extraKeys != null) {
-			addIfNotNull(l, getMethodAnnotation(a, extraKeys));
+			addIfNotNull(l, getAnnotation(a, extraKeys));
 			appendAnnotations(a, extraKeys.getReturnType(), l);
 		}
 
@@ -1089,16 +1089,16 @@ public final class BeanPropertyMeta {
 	 * @param a The annotation to search for.
 	 * @return The annotation, or <jk>null</jk> if it wasn't found.
 	 */
-	public <A extends Annotation> A getAnnotation(Class<A> a) {
+	public <A extends Annotation> A findAnnotation(Class<A> a) {
 		A t = null;
 		if (field != null)
 			t = field.getAnnotation(a);
 		if (t == null && getter != null)
-			t = getMethodAnnotation(a, getter);
+			t = getAnnotation(a, getter);
 		if (t == null && setter != null)
-			t = getMethodAnnotation(a, setter);
+			t = getAnnotation(a, setter);
 		if (t == null && extraKeys != null)
-			t = getMethodAnnotation(a, extraKeys);
+			t = getAnnotation(a, extraKeys);
 		if (t == null)
 			t = ClassUtils.getAnnotation(a, typeMeta.getInnerClass());
 		return t;
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/HeaderStringArray.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/HeaderStringArray.java
index e9639fb..d9d66b6 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/HeaderStringArray.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/HeaderStringArray.java
@@ -14,6 +14,7 @@ package org.apache.juneau.http;
 
 import org.apache.juneau.http.annotation.*;
 import org.apache.juneau.internal.*;
+import org.apache.juneau.jsonschema.annotation.*;
 
 /**
  * Category of headers that consist of a comma-delimited list of string values.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/FormData.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/FormData.java
index 538c8ee..bb5d290 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/FormData.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/FormData.java
@@ -23,6 +23,7 @@ import org.apache.juneau.annotation.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.jsonschema.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.oapi.*;
 
 /**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Header.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Header.java
index b82b87e..55672fa 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Header.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Header.java
@@ -23,6 +23,7 @@ import org.apache.juneau.annotation.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.jsonschema.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.oapi.*;
 
 /**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Path.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Path.java
index 25be34d..8881a2a 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Path.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Path.java
@@ -23,6 +23,7 @@ import org.apache.juneau.annotation.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.jsonschema.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.oapi.*;
 
 /**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Query.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Query.java
index 43f2802..a875586 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Query.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Query.java
@@ -23,6 +23,7 @@ import org.apache.juneau.annotation.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.jsonschema.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.oapi.*;
 
 /**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/ResponseHeader.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/ResponseHeader.java
index d156cbb..dc81978 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/ResponseHeader.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/ResponseHeader.java
@@ -19,6 +19,7 @@ import java.lang.annotation.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.oapi.*;
 
 /**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Tag.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Tag.java
index 7638d32..8617c24 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Tag.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Tag.java
@@ -16,6 +16,8 @@ import static java.lang.annotation.RetentionPolicy.*;
 
 import java.lang.annotation.*;
 
+import org.apache.juneau.jsonschema.annotation.*;
+
 /**
  * Swagger tag annotation.
  *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
index 493ccb2..aec7168 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
@@ -1128,74 +1128,235 @@ public final class ClassUtils {
 		return isParentClass(c, m.getReturnType());
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Method annotations.
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * Returns all annotations of the specified type defined on the specified method.
+	 *
+	 * @param a
+	 * 	The annotation to search for.
+	 * @param m
+	 * 	The method to find the annotation on.
+	 * @param searchParentMethods
+	 * 	If <jk>true</jk>, searches methods with the same signature on the parent classes or interfaces.
+	 * @param searchReturnType
+	 * 	If <jk>true</jk>, searches the return type on the method for the specified annotation.
+	 * @param parentFirst
+	 * 	If <jk>true</jk>, returns the results in parent-to-child order.
+	 * @return
+	 * 	A list of all matching annotations found, or an empty list if none found.
+	 */
+	@SuppressWarnings("unchecked")
+	public static <T extends Annotation> List<T> getAnnotations(Class<T> a, Method m, boolean searchParentMethods, boolean searchReturnType, boolean parentFirst) {
+		List<T> l = new ArrayList<>();
+		List<Method> methods = searchParentMethods ? findMatchingMethods(m) : Collections.singletonList(m);
+		for (Method m2 : methods)
+			for (Annotation a2 :  m2.getAnnotations())
+				if (a.isInstance(a2))
+					l.add((T)a2);
+		if (searchReturnType) {
+			Type t = m.getGenericReturnType();
+			if (Value.isType(t))
+				appendAnnotations(a, Value.getParameterType(t), l);
+			else
+				appendAnnotations(a, t, l);
+		}
+		if (parentFirst)
+			Collections.reverse(l);
+		return l;
+	}
+
 	/**
-	 * Returns the specified annotation on the specified method.
+	 * Shortcut for calling <code>getAnnotations(a, m, <jk>true</jk>, <jk>true</jk>, <jk>false</jk>);</code>
 	 *
 	 * <p>
-	 * Similar to {@link Method#getAnnotation(Class)}, but searches up the parent hierarchy for the annotation
-	 * defined on parent classes and interfaces.
+	 * Annotations are ordered method first, then return class, then return superclasses.
 	 *
-	 * <p>
-	 * Normally, annotations defined on methods of parent classes and interfaces are not inherited by the child methods.
-	 * This utility method gets around that limitation by searching the class hierarchy for the "same" method
-	 * (i.e. the same name and arguments).
+	 * @param a The annotation to look for.
+	 * @param m The method being inspected.
+	 * @return All instances of the annotation with the
+	 */
+	public static <T extends Annotation> List<T> getAnnotations(Class<T> a, Method m) {
+		return getAnnotations(a, m, true, true, false);
+	}
+
+	/**
+	 * Shortcut for calling <code>getAnnotations(a, m, <jk>true</jk>, <jk>true</jk>, <jk>true</jk>);</code>
 	 *
-	 * @param a The annotation to search for.
-	 * @param m The method to search.
-	 * @return The annotation, or <jk>null</jk> if it wasn't found.
+	 * @param a The annotation to look for.
+	 * @param m The method being inspected.
+	 * @return All instances of the annotation with the
 	 */
-	public static <T extends Annotation> T getMethodAnnotation(Class<T> a, Method m) {
-		return getMethodAnnotation(a, m.getDeclaringClass(), m);
+	public static <T extends Annotation> List<T> getAnnotationsParentFirst(Class<T> a, Method m) {
+		return getAnnotations(a, m, true, true, true);
 	}
 
 	/**
-	 * Returns the specified annotation on the specified method.
+	 * Finds the annotation of the specified type defined on the specified method.
 	 *
-	 * <p>
-	 * Similar to {@link Method#getAnnotation(Class)}, but searches up the parent hierarchy for the annotation defined
-	 * on parent classes and interfaces.
+	 * @param a
+	 * 	The annotation to search for.
+	 * @param m
+	 * 	The method to find the annotation on.
+	 * @param searchParentMethods
+	 * 	If <jk>true</jk>, searches methods with the same signature on the parent classes or interfaces.
+	 * 	<br>The search is performed in child-to-parent order.
+	 * @param searchReturnType
+	 * 	If <jk>true</jk>, searches the return type on the method for the specified annotation.
+	 * @return
+	 * 	The annotation if found, or <jk>null</jk> if not.
+	 */
+	@SuppressWarnings("unchecked")
+	public static <T extends Annotation> T getAnnotation(Class<T> a, Method m, boolean searchParentMethods, boolean searchReturnType) {
+		List<Method> methods = searchParentMethods ? findMatchingMethods(m) : Collections.singletonList(m);
+		for (Method m2 : methods)
+			for (Annotation a2 :  m2.getAnnotations())
+				if (a.isInstance(a2))
+					return (T)a2;
+		if (searchReturnType) {
+			Type t = m.getGenericReturnType();
+			if (Value.isType(t))
+				return getAnnotation(a, Value.getParameterType(t));
+			return getAnnotation(a, t);
+		}
+		return null;
+	}
+
+	/**
+	 * Shortcut for calling <code>getAnnotation(a, m, true, true);
 	 *
-	 * <p>
-	 * Normally, annotations defined on methods of parent classes and interfaces are not inherited by the child methods.
-	 * This utility method gets around that limitation by searching the class hierarchy for the "same" method
-	 * (i.e. the same name and arguments).
+	 * @param a
+	 * 	The annotation to search for.
+	 * @param m
+	 * 	The method to find the annotation on.
+	 * @return
+	 * 	The annotation if found, or <jk>null</jk> if not.
+	 */
+	public static <T extends Annotation> T getAnnotation(Class<T> a, Method m) {
+		return getAnnotation(a, m, true, true);
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Method argument annotations.
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * Returns all annotations of the specified type defined on the specified method argument.
 	 *
-	 * @param a The annotation to search for.
-	 * @param c
-	 * 	The child class to start searching from.
-	 * 	Note that it can be a descendant class of the actual declaring class of the method passed in.
-	 * 	This allows you to find annotations on methods overridden by the method passed in.
-	 * @param method The method to search.
-	 * @return The annotation, or <jk>null</jk> if it wasn't found.
-	 */
-	public static <T extends Annotation> T getMethodAnnotation(Class<T> a, Class<?> c, Method method) {
-		for (Method m : c.getDeclaredMethods()) {
-			if (isSameMethod(method, m)) {
-				T t = m.getAnnotation(a);
-				if (t != null)
-					return t;
-			}
-		}
-		Class<?> pc = c.getSuperclass();
-		if (pc != null) {
-			T t = getMethodAnnotation(a, pc, method);
-			if (t != null)
-				return t;
+	 * @param a
+	 * 	The annotation to search for.
+	 * @param m
+	 * 	The method containing the argument to find the annotation on.
+	 * @param index
+	 * 	The argument index position.
+	 * @param searchParentMethods
+	 * 	If <jk>true</jk>, searches methods with the same signature on the parent classes or interfaces.
+	 * @param searchArgType
+	 * 	If <jk>true</jk>, searches the argument type for the specified annotation.
+	 * @param parentFirst
+	 * 	If <jk>true</jk>, returns the results in parent-to-child order.
+	 * @return
+	 * 	A list of all matching annotations found, or an empty list if none found.
+	 */
+	@SuppressWarnings("unchecked")
+	public static <T extends Annotation> List<T> getAnnotations(Class<T> a, Method m, int index, boolean searchParentMethods, boolean searchArgType, boolean parentFirst) {
+		List<T> l = new ArrayList<>();
+		List<Method> methods = searchParentMethods ? findMatchingMethods(m) : Collections.singletonList(m);
+		for (Method m2 : methods)
+			for (Annotation a2 :  m2.getParameterAnnotations()[index])
+				if (a.isInstance(a2))
+					l.add((T)a2);
+		if (searchArgType) {
+			Type t = m.getGenericParameterTypes()[index];
+			if (Value.isType(t))
+				appendAnnotations(a, Value.getParameterType(t), l);
+			else
+				appendAnnotations(a, t, l);
 		}
-		for (Class<?> ic : c.getInterfaces()) {
-			T t = getMethodAnnotation(a, ic, method);
-			if (t != null)
-				return t;
+		if (parentFirst)
+			Collections.reverse(l);
+		return l;
+	}
+
+	/**
+	 * Finds the annotation of the specified type defined on the specified method argument.
+	 *
+	 * @param a
+	 * 	The annotation to search for.
+	 * @param m
+	 * 	The method containing the argument to find the annotation on.
+	 * @param index
+	 * 	The argument index position.
+	 * @param searchParentMethods
+	 * 	If <jk>true</jk>, searches methods with the same signature on the parent classes or interfaces.
+	 * 	<br>The search is performed in child-to-parent order.
+	 * @param searchArgType
+	 * 	If <jk>true</jk>, searches the argument type for the specified annotation.
+	 * @return
+	 * 	The annotation if found, or <jk>null</jk> if not.
+	 */
+	@SuppressWarnings("unchecked")
+	public static <T extends Annotation> T getAnnotation(Class<T> a, Method m, int index, boolean searchParentMethods, boolean searchArgType) {
+		List<Method> methods = searchParentMethods ? findMatchingMethods(m) : Collections.singletonList(m);
+		for (Method m2 : methods)
+			for (Annotation a2 :  m2.getParameterAnnotations()[index])
+				if (a.isInstance(a2))
+					return (T)a2;
+		if (searchArgType) {
+			Type t = m.getGenericParameterTypes()[index];
+			if (Value.isType(t))
+				return getAnnotation(a, Value.getParameterType(t));
+			return getAnnotation(a, t);
 		}
 		return null;
 	}
 
 	/**
+	 * Shortcut for calling <code>getAnnotation(a, m, index, <jk>true</jk>, <jk>true</jk>);</code>
+	 *
+	 * @param a The annotation to check for.
+	 * @param m The method containing the parameter to check.
+	 * @param index The parameter index.
+	 * @return <jk>true</jk> if the {@link #getAnnotation(Class, Method, int)} returns a value.
+	 */
+	public static <T extends Annotation> T getAnnotation(Class<T> a, Method m, int index) {
+		return getAnnotation(a, m, index, true, true);
+	}
+
+	/**
+	 * Shortcut for calling <code>getAnnotations(a, m, index, <jk>true</jk>, <jk>true</jk>, <jk>false</jk>);</code>
+	 *
+	 * @param a The annotation to look for.
+	 * @param m The method containing the parameter.
+	 * @param index The parameter index.
+	 * @return All instances of the annotation with the
+	 */
+	public static <T extends Annotation> List<T> getAnnotations(Class<T> a, Method m, int index) {
+		return getAnnotations(a, m, index, true, true, false);
+	}
+
+	/**
+	 * Shortcut for calling <code>getAnnotations(a, m, index, <jk>true</jk>, <jk>true</jk>, <jk>true</jk>);</code>
+	 *
+	 * @param a The annotation to look for.
+	 * @param m The method containing the parameter.
+	 * @param index The parameter index.
+	 * @return All instances of the annotation with the
+	 */
+	public static <T extends Annotation> List<T> getAnnotationsParentFirst(Class<T> a, Method m, int index) {
+		return getAnnotations(a, m, index, true, true, true);
+	}
+
+	/**
 	 * Given a specific method, finds all declared methods with the same name and arguments on all
 	 * superclasses and interfaces.
 	 *
 	 * @param m The method to find matches against.
-	 * @return All matching methods including the input method itself.
+	 * @return
+	 * 	All matching methods including the input method itself.
+	 * 	Methods are ordered from child-to-parent order.
 	 */
 	public static List<Method> findMatchingMethods(Method m) {
 		return findMatchingMethods(new ArrayList<Method>(), m);
@@ -2257,123 +2418,6 @@ public final class ClassUtils {
 	}
 
 	/**
-	 * Returns the specified annotation if it exists on the specified parameter or parameter type class.
-	 *
-	 * @param a The annotation to check for.
-	 * @param m The method containing the parameter to check.
-	 * @param index The parameter index.
-	 * @return <jk>true</jk> if the {@link #getAnnotation(Class, Method, int)} returns a value.
-	 */
-	@SuppressWarnings("unchecked")
-	public static <T extends Annotation> T getAnnotation(Class<T> a, Method m, int index) {
-		for (Annotation a2 :  m.getParameterAnnotations()[index])
-			if (a.isInstance(a2))
-				return (T)a2;
-		Type t = m.getGenericParameterTypes()[index];
-		if (Value.isType(t))
-			return getAnnotation(a, Value.getParameterType(t));
-		return getAnnotation(a, t);
-	}
-
-	/**
-	 * Returns all annotations defined on the specified parameter and parameter type.
-	 *
-	 * <p>
-	 * Annotations are ordered parameter first, then class, then superclasses.
-	 *
-	 * @param a The annotation to look for.
-	 * @param m The method containing the parameter.
-	 * @param index The parameter index.
-	 * @return All instances of the annotation with the
-	 */
-	@SuppressWarnings("unchecked")
-	public static <T extends Annotation> List<T> getAnnotations(Class<T> a, Method m, int index) {
-		List<T> l = new ArrayList<>();
-		for (Annotation a2 :  m.getParameterAnnotations()[index])
-			if (a.isInstance(a2))
-				l.add((T)a2);
-		Type t = m.getGenericParameterTypes()[index];
-		if (Value.isType(t))
-			appendAnnotations(a, Value.getParameterType(t), l);
-		else
-			appendAnnotations(a, t, l);
-		return l;
-	}
-
-	/**
-	 * Returns all annotations defined on the specified parameter and parameter type.
-	 *
-	 * <p>
-	 * Annotations are ordered parameter superclasses first, then class, then parameter.
-	 *
-	 * @param a The annotation to look for.
-	 * @param m The method containing the parameter.
-	 * @param index The parameter index.
-	 * @return All instances of the annotation with the
-	 */
-	public static <T extends Annotation> List<T> getAnnotationsParentFirst(Class<T> a, Method m, int index) {
-		List<T> l = getAnnotations(a, m, index);
-		Collections.reverse(l);
-		return l;
-	}
-
-	/**
-	 * Returns all annotations defined on the specified method and return type.
-	 *
-	 * <p>
-	 * Annotations are ordered method first, then return class, then return superclasses.
-	 *
-	 * @param a The annotation to look for.
-	 * @param m The method being inspected.
-	 * @return All instances of the annotation with the
-	 */
-	@SuppressWarnings("unchecked")
-	public static <T extends Annotation> List<T> getAnnotations(Class<T> a, Method m) {
-		List<T> l = new ArrayList<>();
-		for (Method m2 : findMatchingMethods(m))
-			for (Annotation a2 :  m2.getAnnotations())
-				if (a.isInstance(a2))
-					l.add((T)a2);
-		Type t = m.getGenericReturnType();
-		if (Value.isType(t))
-			appendAnnotations(a, Value.getParameterType(t), l);
-		else
-			appendAnnotations(a, t, l);
-		return l;
-	}
-
-	/**
-	 * Returns all annotations defined on the specified method and return type.
-	 *
-	 * <p>
-	 * Annotations are ordered return superclass first, then return class, then method.
-	 *
-	 * @param a The annotation to look for.
-	 * @param m The method being inspected.
-	 * @return All instances of the annotation with the
-	 */
-	public static <T extends Annotation> List<T> getAnnotationsParentFirst(Class<T> a, Method m) {
-		List<T> l = getAnnotations(a, m);
-		Collections.reverse(l);
-		return l;
-	}
-
-	/**
-	 * Returns the specified annotation if it exists on the specified method or return type class.
-	 *
-	 * @param a The annotation to check for.
-	 * @param m The method to check.
-	 * @return <jk>true</jk> if the {@link #getAnnotation(Class, Method, int)} returns a value.
-	 */
-	@SuppressWarnings("unchecked")
-	public static <T extends Annotation> T getAnnotation(Class<T> a, Method m) {
-		for (Annotation a2 :  m.getAnnotations())
-			if (a.isInstance(a2))
-				return (T)a2;
-		return getAnnotation(a, m.getGenericReturnType());
-	}
-
-	/**
 	 * Similar to {@link Class#getAnnotation(Class)} except also searches annotations on interfaces.
 	 *
 	 * @param <T> The annotation class type.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaBeanPropertyMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaBeanPropertyMeta.java
index 9544558..6d6f724 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaBeanPropertyMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaBeanPropertyMeta.java
@@ -12,10 +12,9 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.jsonschema;
 
-import static org.apache.juneau.internal.StringUtils.*;
+import java.lang.reflect.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.json.*;
 import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.parser.*;
 
@@ -30,8 +29,7 @@ public class JsonSchemaBeanPropertyMeta extends BeanPropertyMetaExtended {
 	 */
 	public static final JsonSchemaBeanPropertyMeta DEFAULT = new JsonSchemaBeanPropertyMeta();
 
-	private String type, format, description;
-	private Object example;
+	private final ObjectMap schema;
 
 	/**
 	 * Constructor.
@@ -41,73 +39,34 @@ public class JsonSchemaBeanPropertyMeta extends BeanPropertyMetaExtended {
 	public JsonSchemaBeanPropertyMeta(BeanPropertyMeta bpm) {
 		super(bpm);
 
-		if (bpm.getInnerField() != null)
-			findInfo(bpm.getInnerField().getAnnotation(Schema.class));
-		if (bpm.getGetter() != null)
-			findInfo(bpm.getGetter().getAnnotation(Schema.class));
-		if (bpm.getSetter() != null)
-			findInfo(bpm.getSetter().getAnnotation(Schema.class));
-	}
+		this.schema = new ObjectMap();
 
-	private JsonSchemaBeanPropertyMeta() {
-		super(null);
-		this.type = null;
-		this.format = null;
-		this.description = null;
-		this.example = null;
-	}
+		Field field = bpm.getInnerField();
+		Method getter = bpm.getGetter(), setter = bpm.getSetter();
 
-	private void findInfo(Schema js) {
-		if (js == null)
-			return;
-		if (! js.type().isEmpty())
-			type = js.type();
-		if (! js.format().isEmpty())
-			format = js.format();
-		if (js.description().length > 0)
-			description = joinnl(js.description());
-		if (js.example().length > 0) {
-			try {
-				example = JsonParser.DEFAULT.parse(joinnl(js.example()), Object.class);
-			} catch (ParseException e) {
-				throw new BeanRuntimeException(e);
-			}
+		try {
+			if (field != null)
+				schema.appendAll(SchemaUtils.asMap(field.getAnnotation(Schema.class)));
+			if (getter != null)
+				schema.appendAll(SchemaUtils.asMap(getter.getAnnotation(Schema.class)));
+			if (setter != null)
+				schema.appendAll(SchemaUtils.asMap(setter.getAnnotation(Schema.class)));
+		} catch (ParseException e) {
+			throw new RuntimeException(e);
 		}
 	}
 
-	/**
-	 * Returns the {@link Schema#type() @Schema(type)} annotation defined on the class.
-	 *
-	 * @return The value of the annotation, or <jk>null</jk> if not specified.
-	 */
-	protected String getType() {
-		return type;
-	}
-
-	/**
-	 * Returns the {@link Schema#format() @Schema(format)} annotation defined on the class.
-	 *
-	 * @return The value of the annotation, or <jk>null</jk> if not specified.
-	 */
-	protected String getFormat() {
-		return format;
-	}
-
-	/**
-	 * Returns the {@link Schema#description() @Schema(description)} annotation defined on the class.
-	 *
-	 * @return The value of the annotation, or <jk>null</jk> if not specified.
-	 */
-	protected String getDescription() {
-		return description;
+	private JsonSchemaBeanPropertyMeta() {
+		super(null);
+		this.schema = ObjectMap.EMPTY_MAP;
 	}
 
 	/**
-	 * Returns the {@link Schema#example() @Schema(example)} annotation defined on the class.
+	 * Returns the schema information gathered from all the {@link Schema @Schema} annotations on the bean property.
 	 *
-	 * @return The value of the annotation, or <jk>null</jk> if not specified.
+	 * @return The schema information as a generic map.  Never <jk>null</jk>.
 	 */
-	protected Object getExample() {
-		return example;
+	protected ObjectMap getSchema() {
+		return schema;
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaClassMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaClassMeta.java
index fb1dfa0..8b131f8 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaClassMeta.java
@@ -12,13 +12,9 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.jsonschema;
 
-import static org.apache.juneau.internal.StringUtils.*;
-
 import org.apache.juneau.*;
 import org.apache.juneau.internal.*;
-import org.apache.juneau.json.*;
 import org.apache.juneau.jsonschema.annotation.*;
-import org.apache.juneau.parser.*;
 
 /**
  * Metadata on classes specific to the JSON-Schema serializer and pulled from the {@link Schema @Schema} annotation on
@@ -26,32 +22,18 @@ import org.apache.juneau.parser.*;
  */
 public class JsonSchemaClassMeta extends ClassMetaExtended {
 
-	private final Schema jsonSchema;
-	private final String type, format, description;
-	private Object example;
+	private final ObjectMap schema;
 
 	/**
 	 * Constructor.
 	 *
 	 * @param cm The class that this annotation is defined on.
+	 * @throws Exception If invalid <ja>@Schema</ja> definition was encountered.
 	 */
-	public JsonSchemaClassMeta(ClassMeta<?> cm) {
+	public JsonSchemaClassMeta(ClassMeta<?> cm) throws Exception {
 		super(cm);
-		this.jsonSchema = ClassUtils.getAnnotation(Schema.class, getInnerClass());
-		if (jsonSchema != null) {
-			type = nullIfEmpty(jsonSchema.type());
-			format = nullIfEmpty(jsonSchema.format());
-			description = nullIfEmpty(joinnl(jsonSchema.description()));
-			try {
-				example = jsonSchema.example().length == 0 ? null : JsonParser.DEFAULT.parse(joinnl(jsonSchema.example()), Object.class);
-			} catch (ParseException e) {
-				throw new BeanRuntimeException(e);
-			}
-		} else {
-			type = null;
-			format = null;
-			description = null;
-		}
+		Schema s = ClassUtils.getAnnotation(Schema.class, getInnerClass());
+		schema = s == null ? ObjectMap.EMPTY_MAP : SchemaUtils.asMap(s);
 	}
 
 	/**
@@ -59,43 +41,7 @@ public class JsonSchemaClassMeta extends ClassMetaExtended {
 	 *
 	 * @return The value of the annotation, or <jk>null</jk> if not specified.
 	 */
-	protected Schema getAnnotation() {
-		return jsonSchema;
-	}
-
-	/**
-	 * Returns the {@link Schema#type() @Schema(type)} annotation defined on the class.
-	 *
-	 * @return The value of the annotation, or <jk>null</jk> if not specified.
-	 */
-	protected String getType() {
-		return type;
-	}
-
-	/**
-	 * Returns the {@link Schema#format() @Schema(format)} annotation defined on the class.
-	 *
-	 * @return The value of the annotation, or <jk>null</jk> if not specified.
-	 */
-	protected String getFormat() {
-		return format;
-	}
-
-	/**
-	 * Returns the {@link Schema#description() @Schema(description)} annotation defined on the class.
-	 *
-	 * @return The value of the annotation, or <jk>null</jk> if not specified.
-	 */
-	protected String getDescription() {
-		return description;
-	}
-
-	/**
-	 * Returns the {@link Schema#example() @Schema(example)} annotation defined on the class.
-	 *
-	 * @return The value of the annotation, or <jk>null</jk> if not specified.
-	 */
-	protected Object getExample() {
-		return example;
+	protected ObjectMap getSchema() {
+		return schema;
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaGeneratorSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaGeneratorSession.java
index e8cee4e..c11ebad 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaGeneratorSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaGeneratorSession.java
@@ -188,14 +188,12 @@ public class JsonSchemaGeneratorSession extends BeanTraverseSession {
 			type = "string";
 		}
 
-		// Add info from @JsonSchema on bean property.
+		// Add info from @Schema on bean property.
 		if (jsbpm != null) {
-			out.appendIf(false, true, true, "type", jsbpm.getType());
-			out.appendIf(false, true, true, "format", jsbpm.getFormat());
+			out.appendAll(jsbpm.getSchema());
 		}
 
-		out.appendIf(false, true, true, "type", jscm.getType());
-		out.appendIf(false, true, true, "format", jscm.getFormat());
+		out.appendAll(jscm.getSchema());
 
 		out.appendIf(false, true, true, "type", type);
 		out.appendIf(false, true, true, "format", format);
@@ -242,14 +240,7 @@ public class JsonSchemaGeneratorSession extends BeanTraverseSession {
 			}
 		}
 
-		// Add info from @JsonSchema on bean property.
-		if (jsbpm != null) {
-			out.appendIf(false, true, true, "description", jsbpm.getDescription());
-			out.appendIf(false, true, true, "x-example", jsbpm.getExample());
-		}
-
-		out.appendIf(false, true, true, "description", jscm.getDescription());
-		out.appendIf(false, true, true, "x-example", jscm.getExample());
+		out.appendAll(jscm.getSchema());
 
 		out.appendIf(false, true, true, "description", description);
 		out.appendIf(false, true, true, "x-example", example);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/SchemaUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/SchemaUtils.java
new file mode 100644
index 0000000..fa20969
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/SchemaUtils.java
@@ -0,0 +1,190 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.jsonschema;
+
+import static org.apache.juneau.http.annotation.AnnotationUtils.*;
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.jsonschema.annotation.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.utils.*;
+
+/**
+ * Utilities for working with the schema annotations.
+ */
+public class SchemaUtils {
+
+	/**
+	 * Converts the specified <ja>@Schema</ja> annotation into a generic map.
+	 *
+	 * @param a The annotation instance.  Can be <jk>null</jk>.
+	 * @return The schema converted to a map, or and empty map if the annotation was null.
+	 * @throws ParseException
+	 */
+	public static ObjectMap asMap(Schema a) throws ParseException {
+		if (a == null)
+			return ObjectMap.EMPTY_MAP;
+		ObjectMap om = new ObjectMap();
+		if (empty(a))
+			return om;
+		if (a.value().length > 0)
+			om.putAll(parseMap(a.value()));
+	return om
+		.appendSkipEmpty("additionalProperties", toObjectMap(a.additionalProperties()))
+		.appendSkipEmpty("allOf", joinnl(a.allOf()))
+		.appendSkipEmpty("collectionFormat", a.collectionFormat())
+		.appendSkipEmpty("default", joinnl(a._default()))
+		.appendSkipEmpty("discriminator", a.discriminator())
+		.appendSkipEmpty("description", joinnl(a.description()))
+		.appendSkipEmpty("enum", toSet(a._enum()))
+		.appendSkipEmpty("examples", parseMap(a.examples()))
+		.appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum())
+		.appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum())
+		.appendSkipEmpty("externalDocs", merge(om.getObjectMap("externalDocs"), a.externalDocs()))
+		.appendSkipEmpty("format", a.format())
+		.appendSkipEmpty("ignore", a.ignore() ? "true" : null)
+		.appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items()))
+		.appendSkipEmpty("maximum", a.maximum())
+		.appendSkipMinusOne("maxItems", a.maxItems())
+		.appendSkipMinusOne("maxLength", a.maxLength())
+		.appendSkipMinusOne("maxProperties", a.maxProperties())
+		.appendSkipEmpty("minimum", a.minimum())
+		.appendSkipMinusOne("minItems", a.minItems())
+		.appendSkipMinusOne("minLength", a.minLength())
+		.appendSkipMinusOne("minProperties", a.minProperties())
+		.appendSkipEmpty("multipleOf", a.multipleOf())
+		.appendSkipEmpty("pattern", a.pattern())
+		.appendSkipEmpty("properties", toObjectMap(a.properties()))
+		.appendSkipFalse("readOnly", a.readOnly())
+		.appendSkipFalse("required", a.required())
+		.appendSkipEmpty("title", a.title())
+		.appendSkipEmpty("type", a.type())
+		.appendSkipFalse("uniqueItems", a.uniqueItems())
+		.appendSkipEmpty("xml", joinnl(a.xml()))
+		.appendSkipEmpty("x-example", joinnl(a.example()))
+		.appendSkipEmpty("$ref", a.$ref())
+	;
+	}
+
+	private static ObjectMap toObjectMap(String[] ss) throws ParseException {
+		if (ss.length == 0)
+			return null;
+		String s = joinnl(ss);
+		if (s.isEmpty())
+			return null;
+		if (! isObjectMap(s, true))
+			s = "{" + s + "}";
+		return new ObjectMap(s);
+	}
+
+	private static ObjectMap parseMap(Object o) throws ParseException {
+		if (o == null)
+			return null;
+		if (o instanceof String[])
+			o = joinnl((String[])o);
+		if (o instanceof String) {
+			String s = o.toString();
+			if (s.isEmpty())
+				return null;
+			if ("IGNORE".equalsIgnoreCase(s))
+				return new ObjectMap().append("ignore", true);
+			if (! isObjectMap(s, true))
+				s = "{" + s + "}";
+			return new ObjectMap(s);
+		}
+		if (o instanceof ObjectMap)
+			return (ObjectMap)o;
+		throw new ParseException("Unexpected data type ''{0}''.  Expected ObjectMap or String.", o.getClass().getName());
+	}
+
+	private static Set<String> toSet(String[] ss) throws ParseException {
+		if (ss.length == 0)
+			return null;
+		String s = joinnl(ss);
+		if (s.isEmpty())
+			return null;
+		Set<String> set = new ASet<>();
+		for (Object o : StringUtils.parseListOrCdl(s))
+			set.add(o.toString());
+		return set;
+	}
+
+	private static ObjectMap merge(ObjectMap om, Items a) throws ParseException {
+		if (empty(a))
+			return om;
+		if (a.value().length > 0)
+			om.putAll(parseMap(a.value()));
+		return om
+			.appendSkipEmpty("collectionFormat", a.collectionFormat())
+			.appendSkipEmpty("default", joinnl(a._default()))
+			.appendSkipEmpty("enum", toSet(a._enum()))
+			.appendSkipEmpty("format", a.format())
+			.appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum())
+			.appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum())
+			.appendSkipEmpty("items", merge(om.getObjectMap("items"), a.items()))
+			.appendSkipEmpty("maximum", a.maximum())
+			.appendSkipMinusOne("maxItems", a.maxItems())
+			.appendSkipMinusOne("maxLength", a.maxLength())
+			.appendSkipEmpty("minimum", a.minimum())
+			.appendSkipMinusOne("minItems", a.minItems())
+			.appendSkipMinusOne("minLength", a.minLength())
+			.appendSkipEmpty("multipleOf", a.multipleOf())
+			.appendSkipEmpty("pattern", a.pattern())
+			.appendSkipFalse("uniqueItems", a.uniqueItems())
+			.appendSkipEmpty("type", a.type())
+			.appendSkipEmpty("$ref", a.$ref())
+		;
+	}
+
+	private static ObjectMap merge(ObjectMap om, SubItems a) throws ParseException {
+		if (empty(a))
+			return om;
+		if (a.value().length > 0)
+			om.putAll(parseMap(a.value()));
+		return om
+			.appendSkipEmpty("collectionFormat", a.collectionFormat())
+			.appendSkipEmpty("default", joinnl(a._default()))
+			.appendSkipEmpty("enum", toSet(a._enum()))
+			.appendSkipFalse("exclusiveMaximum", a.exclusiveMaximum())
+			.appendSkipFalse("exclusiveMinimum", a.exclusiveMinimum())
+			.appendSkipEmpty("format", a.format())
+			.appendSkipEmpty("items", toObjectMap(a.items()))
+			.appendSkipEmpty("maximum", a.maximum())
+			.appendSkipMinusOne("maxItems", a.maxItems())
+			.appendSkipMinusOne("maxLength", a.maxLength())
+			.appendSkipEmpty("minimum", a.minimum())
+			.appendSkipMinusOne("minItems", a.minItems())
+			.appendSkipMinusOne("minLength", a.minLength())
+			.appendSkipEmpty("multipleOf", a.multipleOf())
+			.appendSkipEmpty("pattern", a.pattern())
+			.appendSkipEmpty("type", a.type())
+			.appendSkipFalse("uniqueItems", a.uniqueItems())
+			.appendSkipEmpty("$ref", a.$ref())
+		;
+	}
+
+	private static ObjectMap merge(ObjectMap om, ExternalDocs a) throws ParseException {
+		if (empty(a))
+			return om;
+		if (a.value().length > 0)
+			om.putAll(parseMap(a.value()));
+		return om
+			.appendSkipEmpty("description", joinnl(a.description()))
+			.appendSkipEmpty("url", a.url())
+		;
+	}
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/ExternalDocs.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/annotation/ExternalDocs.java
similarity index 99%
rename from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/ExternalDocs.java
rename to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/annotation/ExternalDocs.java
index f1a1dad..230f5d4 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/ExternalDocs.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/annotation/ExternalDocs.java
@@ -10,7 +10,7 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.http.annotation;
+package org.apache.juneau.jsonschema.annotation;
 
 import static java.lang.annotation.RetentionPolicy.*;
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Items.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/annotation/Items.java
similarity index 96%
rename from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Items.java
rename to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/annotation/Items.java
index 1bcb9c7..e49ca3d 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Items.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/annotation/Items.java
@@ -10,7 +10,7 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.http.annotation;
+package org.apache.juneau.jsonschema.annotation;
 
 import static java.lang.annotation.RetentionPolicy.*;
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/SubItems.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/annotation/SubItems.java
similarity index 96%
rename from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/SubItems.java
rename to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/annotation/SubItems.java
index 65494f5..ad1d560 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/SubItems.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/annotation/SubItems.java
@@ -10,7 +10,7 @@
 // * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
 // * specific language governing permissions and limitations under the License.                                              *
 // ***************************************************************************************************************************
-package org.apache.juneau.http.annotation;
+package org.apache.juneau.jsonschema.annotation;
 
 import static java.lang.annotation.RetentionPolicy.*;
 
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/AtomFeedResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/AtomFeedResource.java
index 8003521..0d9a984 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/AtomFeedResource.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/AtomFeedResource.java
@@ -21,6 +21,7 @@ import java.net.*;
 import org.apache.juneau.dto.atom.*;
 import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.microservice.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.widget.*;
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/CodeFormatterResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/CodeFormatterResource.java
index 6810329..476fa59 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/CodeFormatterResource.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/CodeFormatterResource.java
@@ -17,6 +17,7 @@ import static org.apache.juneau.http.HttpMethodName.*;
 
 import org.apache.juneau.dto.html5.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/DockerRegistryResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/DockerRegistryResource.java
index 2fa81fa..417e9c1 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/DockerRegistryResource.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/DockerRegistryResource.java
@@ -18,6 +18,7 @@ import java.util.*;
 
 import org.apache.juneau.config.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/JsonSchemaResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/JsonSchemaResource.java
index 27a2bbd..2948858 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/JsonSchemaResource.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/JsonSchemaResource.java
@@ -16,6 +16,7 @@ import static org.apache.juneau.BeanContext.*;
 
 import org.apache.juneau.dto.jsonschema.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.microservice.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.widget.*;
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/MethodExampleResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/MethodExampleResource.java
index 9cc560f..304fba6 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/MethodExampleResource.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/MethodExampleResource.java
@@ -16,6 +16,7 @@ import java.util.*;
 
 import org.apache.juneau.http.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.helper.*;
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java
index 0473467..9bd8eed 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java
@@ -24,6 +24,7 @@ import javax.imageio.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PredefinedLabelsResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PredefinedLabelsResource.java
index 689b597..80ef270 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PredefinedLabelsResource.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PredefinedLabelsResource.java
@@ -15,6 +15,7 @@ package org.apache.juneau.examples.rest;
 import org.apache.juneau.dto.*;
 import org.apache.juneau.examples.addressbook.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.helper.*;
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RequestEchoResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RequestEchoResource.java
index 6808e4d..50cd9bd 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RequestEchoResource.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RequestEchoResource.java
@@ -18,6 +18,7 @@ import javax.servlet.*;
 import javax.servlet.http.*;
 
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.converters.*;
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SampleRemoteInterfaceServlet.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SampleRemoteInterfaceServlet.java
index 5001515..ab12d6e 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SampleRemoteInterfaceServlet.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SampleRemoteInterfaceServlet.java
@@ -17,6 +17,7 @@ import java.util.Map;
 
 import org.apache.juneau.examples.addressbook.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.remote.*;
 
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SqlQueryResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SqlQueryResource.java
index a0507ea..b5716e5 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SqlQueryResource.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SqlQueryResource.java
@@ -25,6 +25,7 @@ import org.apache.juneau.dto.*;
 import org.apache.juneau.dto.html5.*;
 import org.apache.juneau.http.annotation.*;
 import org.apache.juneau.http.annotation.Body;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.exception.*;
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 8517f25..eeb0854 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
@@ -23,6 +23,7 @@ import org.apache.juneau.dto.html5.*;
 import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.annotation.*;
 import org.apache.juneau.http.annotation.Body;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.exception.*;
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/TempDirResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/TempDirResource.java
index 25ba5e2..120c1d6 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/TempDirResource.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/TempDirResource.java
@@ -24,6 +24,7 @@ import org.apache.commons.fileupload.servlet.*;
 import org.apache.commons.io.*;
 import org.apache.juneau.dto.html5.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.microservice.resources.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/UrlEncodedFormResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/UrlEncodedFormResource.java
index d030a35..265918a 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/UrlEncodedFormResource.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/UrlEncodedFormResource.java
@@ -21,6 +21,7 @@ import org.apache.juneau.annotation.*;
 import org.apache.juneau.dto.html5.*;
 import org.apache.juneau.http.annotation.*;
 import org.apache.juneau.http.annotation.Body;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.widget.*;
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java
index b070e06..bec95c1 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java
@@ -26,6 +26,7 @@ import org.apache.juneau.encoders.*;
 import org.apache.juneau.examples.addressbook.*;
 import org.apache.juneau.examples.rest.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.microservice.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
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 6fce0cc..f612025 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
@@ -26,6 +26,7 @@ import org.apache.juneau.dto.html5.*;
 import org.apache.juneau.http.annotation.*;
 import org.apache.juneau.http.annotation.Body;
 import org.apache.juneau.http.annotation.Header;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.microservice.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/FormDataAnnotationTest.java b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/FormDataAnnotationTest.java
index dd49872..070140f 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/FormDataAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/FormDataAnnotationTest.java
@@ -23,6 +23,7 @@ import java.util.concurrent.atomic.*;
 import org.apache.juneau.*;
 import org.apache.juneau.http.annotation.*;
 import org.apache.juneau.http.annotation.Header;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
 import org.apache.juneau.rest.mock.*;
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/HeaderAnnotationTest.java b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/HeaderAnnotationTest.java
index 7cb54c9..3faa860 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/HeaderAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/HeaderAnnotationTest.java
@@ -22,6 +22,7 @@ import java.util.concurrent.atomic.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
 import org.apache.juneau.rest.mock.*;
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/PathAnnotationTest.java b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/PathAnnotationTest.java
index ecf25d1..d9df505 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/PathAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/PathAnnotationTest.java
@@ -22,6 +22,7 @@ import java.util.concurrent.atomic.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
 import org.apache.juneau.rest.mock.*;
diff --git a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/QueryAnnotationTest.java b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/QueryAnnotationTest.java
index af93f36..0435233 100644
--- a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/QueryAnnotationTest.java
+++ b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/QueryAnnotationTest.java
@@ -23,6 +23,7 @@ import java.util.concurrent.atomic.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
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 c3d0782..a482968 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
@@ -3215,8 +3215,8 @@ public final class RestContext extends BeanContext {
 				_destroyMethodParams = new ArrayList<>();
 
 			for (java.lang.reflect.Method method : resourceClass.getMethods()) {
-				if (method.isAnnotationPresent(RestMethod.class)) {
-					RestMethod a = method.getAnnotation(RestMethod.class);
+				RestMethod a = ClassUtils.getAnnotation(RestMethod.class, method);
+				if (a != null) {
 					methodsFound.add(method.getName() + "," + a.name() + "," + a.path());
 					try {
 						if (! isPublic(method))
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/SwaggerGenerator.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/SwaggerGenerator.java
index dd9c551..fd1c9b4 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/SwaggerGenerator.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/SwaggerGenerator.java
@@ -26,13 +26,13 @@ import org.apache.juneau.dto.swagger.*;
 import org.apache.juneau.http.*;
 import org.apache.juneau.http.annotation.*;
 import org.apache.juneau.http.annotation.Contact;
-import org.apache.juneau.http.annotation.Items;
 import org.apache.juneau.http.annotation.License;
 import org.apache.juneau.http.annotation.Tag;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.jsonschema.*;
 import org.apache.juneau.jsonschema.annotation.*;
+import org.apache.juneau.jsonschema.annotation.Items;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.util.*;
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/MethodSwagger.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/MethodSwagger.java
index 1ad9fee..5fd9639 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/MethodSwagger.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/MethodSwagger.java
@@ -12,7 +12,7 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.rest.annotation;
 
-import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 
 /**
  * Extended annotation for {@link RestMethod#swagger() RestMethod.swagger()}.
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResourceSwagger.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResourceSwagger.java
index f852d4e..1aae95b 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResourceSwagger.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/ResourceSwagger.java
@@ -13,6 +13,7 @@
 package org.apache.juneau.rest.annotation;
 
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.jsonschema.annotation.*;
 
 /**
  * Extended annotation for {@link RestResource#swagger() @RestResource(swagger)}.
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/AnnotationInheritanceTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/AnnotationInheritanceTest.java
new file mode 100644
index 0000000..3f53930
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/AnnotationInheritanceTest.java
@@ -0,0 +1,48 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.annotation;
+
+import org.junit.*;
+import org.junit.runners.*;
+
+/**
+ * Tests inheritance of annotations from interfaces.
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class AnnotationInheritanceTest {
+
+	//=================================================================================================================
+	// @Body on parameter
+	//=================================================================================================================
+
+//	@RestResource(serializers=SimpleJsonSerializer.class, parsers=JsonParser.class, defaultAccept="text/json")
+//	public static interface IA {
+//		@RestMethod(name=PUT, path="/String")
+//		public String a01(@Body String b);
+//	}
+//
+//	public static class A implements IA {
+//
+//		@Override
+//		public String a01(String b) {
+//			return b;
+//		}
+//	}
+//
+//	private static MockRest a = MockRest.create(A.class);
+//
+//	@Test
+//	public void a01a_onParameter_String() throws Exception {
+//	//	a.put("/String", "'foo'").json().execute().assertBody("'foo'");
+//	}
+}
diff --git a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/QueryAnnotationTest.java b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/QueryAnnotationTest.java
index a67be04..2ef0bb1 100644
--- a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/QueryAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/QueryAnnotationTest.java
@@ -21,8 +21,8 @@ import java.util.*;
 import org.apache.juneau.*;
 import org.apache.juneau.dto.swagger.*;
 import org.apache.juneau.http.annotation.*;
-import org.apache.juneau.http.annotation.Items;
 import org.apache.juneau.json.*;
+import org.apache.juneau.jsonschema.annotation.Items;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.mock.*;
 import org.junit.*;