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.*;