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 32ab891 Tests.
32ab891 is described below
commit 32ab891932efcb17631915b8d53405af73e41d80
Author: JamesBognar <[email protected]>
AuthorDate: Sun Aug 5 13:08:25 2018 -0400
Tests.
---
.../src/test/java/org/apache/juneau/ValueTest.java | 27 +-
.../http/annotation/AnnotationUtilsTest.java | 203 +++++++++
.../org/apache/juneau/dto/swagger/Swagger.java | 42 ++
.../main/java/org/apache/juneau/BeanSession.java | 1 -
.../src/main/java/org/apache/juneau/Value.java | 16 +-
.../juneau/http/annotation/AnnotationUtils.java | 63 ++-
.../org/apache/juneau/http/annotation/Contact.java | 3 -
.../juneau/http/annotation/ExternalDocs.java | 6 +
.../org/apache/juneau/http/annotation/Items.java | 3 -
.../org/apache/juneau/http/annotation/License.java | 3 -
.../org/apache/juneau/http/annotation/RBody.java | 21 -
.../org/apache/juneau/http/annotation/RStatus.java | 20 -
.../apache/juneau/http/annotation/Response.java | 2 +-
.../juneau/http/annotation/ResponseBody.java | 2 +-
.../juneau/http/annotation/ResponseHeader.java | 2 +-
.../org/apache/juneau/http/annotation/Schema.java | 3 -
.../apache/juneau/http/annotation/SubItems.java | 3 -
.../org/apache/juneau/http/annotation/Tag.java | 3 -
.../juneau/httppart/HttpPartSchemaBuilder.java | 8 +-
.../org/apache/juneau/internal/ClassUtils.java | 187 +++++----
juneau-doc/src/main/javadoc/overview.html | 120 ++++--
.../10.Transforms/02.PerMediaTypePojoSwaps.html | 22 +-
.../09.HttpPartAnnotations/08.RequestBean.html | 63 +--
.../09.HttpPartAnnotations/09.ResponseBody.html | 75 ++++
.../org/apache/juneau/rest/SwaggerGenerator.java | 48 ++-
.../juneau/rest/BasicRestInfoProviderTest.java | 2 +-
.../rest/annotation/ResponseAnnotationTest.java | 6 +-
.../annotation/ResponseBodyAnnotationTest.java | 452 +++++++++++++++++++++
28 files changed, 1167 insertions(+), 239 deletions(-)
diff --git
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/ValueTest.java
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/ValueTest.java
index 3414351..0a1ef1b 100644
---
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/ValueTest.java
+++
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/ValueTest.java
@@ -14,6 +14,10 @@ package org.apache.juneau;
import static org.junit.Assert.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.internal.*;
import org.junit.*;
/**
@@ -21,6 +25,10 @@ import org.junit.*;
*/
public class ValueTest {
+
//-----------------------------------------------------------------------------------------------------------------
+ // Value defined on parent class.
+
//-----------------------------------------------------------------------------------------------------------------
+
public static class A extends Value<A1>{}
public static class A1 {}
@@ -29,14 +37,29 @@ public class ValueTest {
assertEquals(A1.class, Value.getParameterType(A.class));
}
+
//-----------------------------------------------------------------------------------------------------------------
+ // Value used in parameter.
+
//-----------------------------------------------------------------------------------------------------------------
public static class B {
public void b(Value<B1> b1) {};
-
}
public static class B1 {}
@Test
- public void testParameter() throws Exception {
+ public void testOnParameter() throws Exception {
assertEquals(B1.class,
Value.getParameterType(B.class.getMethod("b", Value.class), 0));
}
+
+
//-----------------------------------------------------------------------------------------------------------------
+ // Value used on parameter of parameterized-type.
+
//-----------------------------------------------------------------------------------------------------------------
+ public interface C {
+ void m1(Value<List<Integer>> v);
+ }
+
+ @Test
+ public void testOnParameterType() throws Exception {
+ Type t = Value.getParameterType(C.class.getMethod("m1",
Value.class), 0);
+ assertEquals("List<Integer>", ClassUtils.getSimpleName(t));
+ }
}
diff --git
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/http/annotation/AnnotationUtilsTest.java
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/http/annotation/AnnotationUtilsTest.java
new file mode 100644
index 0000000..f9a9937
--- /dev/null
+++
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/http/annotation/AnnotationUtilsTest.java
@@ -0,0 +1,203 @@
+//
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file *
+// * distributed with this work for additional information regarding copyright
ownership. The ASF licenses this file *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance *
+// * with the License. You may obtain a copy of the License at
*
+// *
*
+// * http://www.apache.org/licenses/LICENSE-2.0
*
+// *
*
+// * Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
express or implied. See the License for the *
+// * specific language governing permissions and limitations under the
License. *
+//
***************************************************************************************************************************
+package org.apache.juneau.http.annotation;
+
+import static org.junit.Assert.*;
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
+import static org.apache.juneau.http.annotation.AnnotationUtils.*;
+
+import java.lang.annotation.*;
+import java.lang.reflect.*;
+
+import org.apache.juneau.httppart.*;
+import org.junit.*;
+import org.junit.runners.*;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class AnnotationUtilsTest {
+
+
//-----------------------------------------------------------------------------------------------------------------
+ // Test empty checks
+
//-----------------------------------------------------------------------------------------------------------------
+
+ @Target(TYPE)
+ @Retention(RUNTIME)
+ public @interface X {
+ Contact x1() default @Contact;
+ ExternalDocs x2() default @ExternalDocs;
+ License x3() default @License;
+ Schema x4() default @Schema;
+ SubItems x5() default @SubItems;
+ Items x6() default @Items;
+ }
+
+ @Body
+ @Response
+ @ResponseBody
+ @ResponseHeader
+ @X
+ public static class A01 {
+ @Query @Header @FormData @Path @Schema
+ public int f1;
+ }
+
+ @Test
+ public void testEmpty() throws Exception {
+ assertTrue(empty(A01.class.getAnnotation(Body.class)));
+ assertTrue(empty(A01.class.getAnnotation(Response.class)));
+ assertTrue(empty(A01.class.getAnnotation(ResponseBody.class)));
+
assertTrue(empty(A01.class.getAnnotation(ResponseHeader.class)));
+
+ X x = A01.class.getAnnotation(X.class);
+ assertTrue(empty(x.x1()));
+ assertTrue(empty(x.x2()));
+ assertTrue(empty(x.x3()));
+ assertTrue(empty(x.x4()));
+ assertTrue(empty(x.x5()));
+ assertTrue(empty(x.x6()));
+
+ Field f = A01.class.getField("f1");
+ assertTrue(empty(f.getAnnotation(Query.class)));
+ assertTrue(empty(f.getAnnotation(Header.class)));
+ assertTrue(empty(f.getAnnotation(FormData.class)));
+ assertTrue(empty(f.getAnnotation(Path.class)));
+ }
+
+ public static class B01 {
+ public int f1;
+ }
+
+ @Test
+ public void testEmptyNonExistent() throws Exception {
+ assertTrue(empty(B01.class.getAnnotation(Body.class)));
+ assertTrue(empty(B01.class.getAnnotation(Response.class)));
+ assertTrue(empty(B01.class.getAnnotation(ResponseBody.class)));
+
assertTrue(empty(B01.class.getAnnotation(ResponseHeader.class)));
+
+ assertTrue(empty((Contact)null));
+ assertTrue(empty((ExternalDocs)null));
+ assertTrue(empty((License)null));
+ assertTrue(empty((Schema)null));
+ assertTrue(empty((Items)null));
+ assertTrue(empty((SubItems)null));
+
+ Field f = B01.class.getField("f1");
+ assertTrue(empty(f.getAnnotation(Query.class)));
+ assertTrue(empty(f.getAnnotation(Header.class)));
+ assertTrue(empty(f.getAnnotation(FormData.class)));
+ assertTrue(empty(f.getAnnotation(Path.class)));
+ }
+
+ @Test
+ public void testAllEmpty1() {
+ assertTrue(allEmpty(new String[0]));
+ assertTrue(allEmpty(""));
+ assertTrue(allEmpty(null,""));
+ assertFalse(allEmpty(null,"","x"));
+ }
+
+ @Test
+ public void testAllEmpty2() {
+ assertTrue(allEmpty(new String[0],new String[0]));
+ assertTrue(allEmpty(null,new String[0]));
+ assertTrue(allEmpty(null,new String[]{""}));
+ assertFalse(allEmpty(null,new String[]{"x"}));
+ }
+
+ @Test
+ public void testAllFalse() {
+ assertTrue(allFalse());
+ assertTrue(allFalse(false));
+ assertTrue(allFalse(false,false));
+ assertFalse(allFalse(false,true));
+ assertFalse(allFalse(true));
+ }
+
+ @Test
+ public void testAllMinusOne() {
+ assertTrue(allMinusOne());
+ assertTrue(allMinusOne(-1));
+ assertTrue(allMinusOne(-1,-1));
+ assertFalse(allMinusOne(-1,0));
+ assertFalse(allMinusOne(0));
+ }
+
+ @Test
+ public void testAllMinusOneLongs() {
+ assertTrue(allMinusOne(-1l));
+ assertTrue(allMinusOne(-1l,-1l));
+ assertFalse(allMinusOne(-1l,0l));
+ assertFalse(allMinusOne(0l));
+ }
+
+ @Body public static class C01a {}
+ @Body(usePartParser=true) public static class C01b {}
+ @Body(schema=@Schema) public static class C01c {}
+ @Body(schema=@Schema(description="foo")) public static class C01d {}
+ @Body(partParser=OpenApiPartParser.class) public static class C01e {}
+
+ @Test
+ public void usePartParserBody() {
+
assertFalse(usePartParser(C01a.class.getAnnotation(Body.class)));
+ assertTrue(usePartParser(C01b.class.getAnnotation(Body.class)));
+
assertFalse(usePartParser(C01c.class.getAnnotation(Body.class)));
+ assertTrue(usePartParser(C01d.class.getAnnotation(Body.class)));
+ assertTrue(usePartParser(C01e.class.getAnnotation(Body.class)));
+ }
+
+ @Body public static class D01a {}
+ @Body(usePartSerializer=true) public static class D01b {}
+ @Body(schema=@Schema) public static class D01c {}
+ @Body(schema=@Schema(description="foo")) public static class D01d {}
+ @Body(partSerializer=OpenApiPartSerializer.class) public static class
D01e {}
+
+ @Test
+ public void usePartSerializerBody() {
+
assertFalse(usePartSerializer(D01a.class.getAnnotation(Body.class)));
+
assertTrue(usePartSerializer(D01b.class.getAnnotation(Body.class)));
+
assertFalse(usePartSerializer(D01c.class.getAnnotation(Body.class)));
+
assertTrue(usePartSerializer(D01d.class.getAnnotation(Body.class)));
+
assertTrue(usePartSerializer(D01e.class.getAnnotation(Body.class)));
+ }
+
+ @ResponseBody public static class E01a {}
+ @ResponseBody(usePartSerializer=true) public static class E01b {}
+ @ResponseBody(schema=@Schema) public static class E01c {}
+ @ResponseBody(schema=@Schema(description="foo")) public static class
E01d {}
+ @ResponseBody(partSerializer=OpenApiPartSerializer.class) public static
class E01e {}
+
+ @Test
+ public void usePartSerializerResponseBody() {
+
assertFalse(usePartSerializer(E01a.class.getAnnotation(ResponseBody.class)));
+
assertTrue(usePartSerializer(E01b.class.getAnnotation(ResponseBody.class)));
+
assertFalse(usePartSerializer(E01c.class.getAnnotation(ResponseBody.class)));
+
assertTrue(usePartSerializer(E01d.class.getAnnotation(ResponseBody.class)));
+
assertTrue(usePartSerializer(E01e.class.getAnnotation(ResponseBody.class)));
+ }
+
+ @Response public static class F01a {}
+ @Response(usePartSerializer=true) public static class F01b {}
+ @Response(schema=@Schema) public static class F01c {}
+ @Response(schema=@Schema(description="foo")) public static class F01d {}
+ @Response(partSerializer=OpenApiPartSerializer.class) public static
class F01e {}
+
+ @Test
+ public void usePartSerializerResponse() {
+
assertFalse(usePartSerializer(F01a.class.getAnnotation(Response.class)));
+
assertTrue(usePartSerializer(F01b.class.getAnnotation(Response.class)));
+
assertFalse(usePartSerializer(F01c.class.getAnnotation(Response.class)));
+
assertTrue(usePartSerializer(F01d.class.getAnnotation(Response.class)));
+
assertTrue(usePartSerializer(F01e.class.getAnnotation(Response.class)));
+ }
+}
\ No newline at end of file
diff --git
a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Swagger.java
b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Swagger.java
index f8ab27d..e4d2943 100644
---
a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Swagger.java
+++
b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/Swagger.java
@@ -614,6 +614,48 @@ public class Swagger extends SwaggerElement {
}
/**
+ * Shortcut for calling <code>getPaths().get(path);</code>
+ *
+ * @param path The path (e.g. <js>"/foo"</js>).
+ * @return The operation map for the specified path, or <jk>null</jk>
if it doesn't exist.
+ */
+ public OperationMap getPath(String path) {
+ return getPaths().get(path);
+ }
+
+ /**
+ * Shortcut for calling
<code>getPaths().get(path).get(operation);</code>
+ *
+ * @param path The path (e.g. <js>"/foo"</js>).
+ * @param operation The HTTP operation (e.g. <js>"get"</js>).
+ * @return The operation for the specified path and operation id, or
<jk>null</jk> if it doesn't exist.
+ */
+ public Operation getOperation(String path, String operation) {
+ OperationMap om = getPath(path);
+ if (om == null)
+ return null;
+ return om.get(operation);
+ }
+
+ /**
+ * Shortcut for calling
<code>getPaths().get(path).get(operation).getResponse(status);</code>
+ *
+ * @param path The path (e.g. <js>"/foo"</js>).
+ * @param operation The HTTP operation (e.g. <js>"get"</js>).
+ * @param status The HTTP response status (e.g. <js>"200"</js>).
+ * @return The operation for the specified path and operation id, or
<jk>null</jk> if it doesn't exist.
+ */
+ public ResponseInfo getResponseInfo(String path, String operation,
Object status) {
+ OperationMap om = getPath(path);
+ if (om == null)
+ return null;
+ Operation op = om.get(operation);
+ if (op == null)
+ return null;
+ return op.getResponse(status);
+ }
+
+ /**
* Bean property setter: <property>paths</property>.
*
* <p>
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
index 784c374..ff363c5 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
@@ -76,7 +76,6 @@ public class BeanSession extends Session {
}
/**
- /**
* Converts the specified value to the specified class type.
*
* <p>
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Value.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Value.java
index 45752f0..aefab7c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Value.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Value.java
@@ -44,7 +44,7 @@ public class Value<T> {
* @param i The index of the parameter.
* @return The parameter type of the value, or <jk>null</jk> if the
method parameter is not of type <code>Value</code>.
*/
- public static Class<?> getParameterType(Method m, int i) {
+ public static Type getParameterType(Method m, int i) {
return getParameterType(m.getGenericParameterTypes()[i]);
}
@@ -54,17 +54,13 @@ public class Value<T> {
* @param t The type to find the parameter type of.
* @return The parameter type of the value, or <jk>null</jk> if the
type is not a subclass of <code>Value</code>.
*/
- public static Class<?> getParameterType(Type t) {
+ public static Type getParameterType(Type t) {
if (t instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType)t;
if (pt.getRawType() == Value.class) {
Type[] ta = pt.getActualTypeArguments();
- if (ta.length > 0) {
- Type t2 = ta[0];
- if (t2 instanceof Class) {
- return (Class<?>)t2;
- }
- }
+ if (ta.length > 0)
+ return ta[0];
}
} else if (t instanceof Class) {
Class<?> c = (Class<?>)t;
@@ -83,8 +79,8 @@ public class Value<T> {
* @return <jk>true</jk> if the specified type is this class.
*/
public static boolean isType(Type t) {
- return
- (t instanceof ParameterizedType &&
((ParameterizedType)t).getRawType() == Value.class)
+ return
+ (t instanceof ParameterizedType &&
((ParameterizedType)t).getRawType() == Value.class)
|| (t instanceof Class &&
Value.class.isAssignableFrom((Class<?>)t));
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/AnnotationUtils.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/AnnotationUtils.java
index 5044fc3..f22c67a 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/AnnotationUtils.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/AnnotationUtils.java
@@ -12,6 +12,8 @@
//
***************************************************************************************************************************
package org.apache.juneau.http.annotation;
+import org.apache.juneau.httppart.*;
+
/**
* Various reusable utility methods when working with annotations.
*/
@@ -253,9 +255,10 @@ public class AnnotationUtils {
* @return <jk>true</jk> if all the specified strings are empty or null.
*/
protected static boolean allEmpty(String...strings) {
- for (String s : strings)
- if (s != null && ! s.isEmpty())
- return false;
+ if (strings != null)
+ for (String s : strings)
+ if (s != null && ! s.isEmpty())
+ return false;
return true;
}
@@ -267,7 +270,7 @@ public class AnnotationUtils {
*/
protected static boolean allEmpty(String[]...strings) {
for (String[] s : strings)
- if (s.length != 0 || ! allEmpty(s))
+ if (s != null && s.length > 0 && ! allEmpty(s))
return false;
return true;
}
@@ -297,4 +300,56 @@ public class AnnotationUtils {
return false;
return true;
}
+
+ /**
+ * Returns <jk>true</jk> if the part parser should be used on the
specified part.
+ *
+ * @param a The annotation to check.
+ * @return <jk>true</jk> if the part parser should be used on the
specified part.
+ */
+ public static boolean usePartParser(Body a) {
+ return
+ a.usePartParser()
+ || a.partParser() != HttpPartParser.Null.class
+ || ! empty(a.schema());
+ }
+
+ /**
+ * Returns <jk>true</jk> if the part serializer should be used on the
specified part.
+ *
+ * @param a The annotation to check.
+ * @return <jk>true</jk> if the part serializer should be used on the
specified part.
+ */
+ public static boolean usePartSerializer(Body a) {
+ return
+ a.usePartSerializer()
+ || a.partSerializer() != HttpPartSerializer.Null.class
+ || ! empty(a.schema());
+ }
+
+ /**
+ * Returns <jk>true</jk> if the part serializer should be used on the
specified part.
+ *
+ * @param a The annotation to check.
+ * @return <jk>true</jk> if the part serializer should be used on the
specified part.
+ */
+ public static boolean usePartSerializer(ResponseBody a) {
+ return
+ a.usePartSerializer()
+ || a.partSerializer() != HttpPartSerializer.Null.class
+ || ! empty(a.schema());
+ }
+
+ /**
+ * Returns <jk>true</jk> if the part serializer should be used on the
specified part.
+ *
+ * @param a The annotation to check.
+ * @return <jk>true</jk> if the part serializer should be used on the
specified part.
+ */
+ public static boolean usePartSerializer(Response a) {
+ return
+ a.usePartSerializer()
+ || a.partSerializer() != HttpPartSerializer.Null.class
+ || ! empty(a.schema());
+ }
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Contact.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Contact.java
index fc528be..f952779 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Contact.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Contact.java
@@ -12,7 +12,6 @@
//
***************************************************************************************************************************
package org.apache.juneau.http.annotation;
-import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.*;
@@ -60,9 +59,7 @@ import java.lang.annotation.*;
* </ul>
*/
@Documented
-@Target({PARAMETER,TYPE})
@Retention(RUNTIME)
-@Inherited
public @interface Contact {
/**
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/http/annotation/ExternalDocs.java
index 73a3c57..92b53fe 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/http/annotation/ExternalDocs.java
@@ -12,6 +12,10 @@
//
***************************************************************************************************************************
package org.apache.juneau.http.annotation;
+import static java.lang.annotation.RetentionPolicy.*;
+
+import java.lang.annotation.*;
+
/**
* Swagger external documentation annotation.
*
@@ -51,6 +55,8 @@ package org.apache.juneau.http.annotation;
* <li class='link'><a class="doclink"
href="https://swagger.io/specification/v2/#externalDocumentationObject">Swagger
Specification > External Documentation Object</a>
* </ul>
*/
+@Documented
+@Retention(RUNTIME)
public @interface ExternalDocs {
/**
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/http/annotation/Items.java
index 5d0d886..291b6e7 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/http/annotation/Items.java
@@ -12,7 +12,6 @@
//
***************************************************************************************************************************
package org.apache.juneau.http.annotation;
-import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.*;
@@ -80,9 +79,7 @@ import org.apache.juneau.httppart.*;
* </ul>
*/
@Documented
-@Target({PARAMETER,TYPE})
@Retention(RUNTIME)
-@Inherited
public @interface Items {
/**
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/License.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/License.java
index fad1959..764e8dd 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/License.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/License.java
@@ -12,7 +12,6 @@
//
***************************************************************************************************************************
package org.apache.juneau.http.annotation;
-import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.*;
@@ -57,9 +56,7 @@ import java.lang.annotation.*;
* </ul>
*/
@Documented
-@Target({PARAMETER,TYPE})
@Retention(RUNTIME)
-@Inherited
public @interface License {
/**
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/RBody.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/RBody.java
deleted file mode 100644
index ebe9069..0000000
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/RBody.java
+++ /dev/null
@@ -1,21 +0,0 @@
-//
***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file *
-// * distributed with this work for additional information regarding copyright
ownership. The ASF licenses this file *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance *
-// * with the License. You may obtain a copy of the License at
*
-// *
*
-// * http://www.apache.org/licenses/LICENSE-2.0
*
-// *
*
-// * Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
express or implied. See the License for the *
-// * specific language governing permissions and limitations under the
License. *
-//
***************************************************************************************************************************
-package org.apache.juneau.http.annotation;
-
-/**
- * TODO
- *
- */
-public class RBody {
-
-}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/RStatus.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/RStatus.java
deleted file mode 100644
index 566e9e6..0000000
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/RStatus.java
+++ /dev/null
@@ -1,20 +0,0 @@
-//
***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file *
-// * distributed with this work for additional information regarding copyright
ownership. The ASF licenses this file *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance *
-// * with the License. You may obtain a copy of the License at
*
-// *
*
-// * http://www.apache.org/licenses/LICENSE-2.0
*
-// *
*
-// * Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
express or implied. See the License for the *
-// * specific language governing permissions and limitations under the
License. *
-//
***************************************************************************************************************************
-package org.apache.juneau.http.annotation;
-
-/**
- * TODO
- *
- */
-public class RStatus {
-}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Response.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Response.java
index 20bd1ec..1ba720d 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Response.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Response.java
@@ -48,7 +48,7 @@ import org.apache.juneau.jsonschema.*;
* </ul>
*/
@Documented
-@Target({TYPE})
+@Target({PARAMETER,TYPE})
@Retention(RUNTIME)
@Inherited
public @interface Response {
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/ResponseBody.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/ResponseBody.java
index 271cdfb..e1aafcb 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/ResponseBody.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/ResponseBody.java
@@ -27,7 +27,7 @@ import org.apache.juneau.jsonschema.*;
* TODO
*/
@Documented
-@Target({PARAMETER,TYPE,METHOD})
+@Target({PARAMETER,METHOD,TYPE})
@Retention(RUNTIME)
@Inherited
public @interface ResponseBody {
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 7d2992c..fc8527a 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
@@ -82,7 +82,7 @@ import org.apache.juneau.httppart.*;
* </ul>
*/
@Documented
-@Target({PARAMETER,TYPE,METHOD})
+@Target({PARAMETER,METHOD,TYPE})
@Retention(RUNTIME)
@Inherited
public @interface ResponseHeader {
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Schema.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Schema.java
index 4eebb27..222ca28 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Schema.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Schema.java
@@ -12,7 +12,6 @@
//
***************************************************************************************************************************
package org.apache.juneau.http.annotation;
-import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.*;
@@ -75,9 +74,7 @@ import org.apache.juneau.httppart.*;
* </ul>
*/
@Documented
-@Target({PARAMETER,TYPE})
@Retention(RUNTIME)
-@Inherited
public @interface Schema {
/**
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/http/annotation/SubItems.java
index a2b200d..c55352e 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/http/annotation/SubItems.java
@@ -12,7 +12,6 @@
//
***************************************************************************************************************************
package org.apache.juneau.http.annotation;
-import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.*;
@@ -34,9 +33,7 @@ import java.lang.annotation.*;
* </ul>
*/
@Documented
-@Target({PARAMETER,TYPE})
@Retention(RUNTIME)
-@Inherited
public @interface SubItems {
/**
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 304cb32..7d8cd6f 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
@@ -12,7 +12,6 @@
//
***************************************************************************************************************************
package org.apache.juneau.http.annotation;
-import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.*;
@@ -62,9 +61,7 @@ import java.lang.annotation.*;
* </ul>
*/
@Documented
-@Target({PARAMETER,TYPE})
@Retention(RUNTIME)
-@Inherited
public @interface Tag {
/**
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java
index 906a170..3ecef7e 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java
@@ -128,15 +128,15 @@ public class HttpPartSchemaBuilder {
allowEmptyValue(! a.required());
serializer(a.partSerializer());
parser(a.partParser());
- usePartSerializer(a.usePartSerializer() || a.partSerializer()
!= HttpPartSerializer.Null.class);
- usePartParser(a.usePartParser() || a.partParser() !=
HttpPartParser.Null.class);
+ usePartSerializer(AnnotationUtils.usePartSerializer(a));
+ usePartParser(AnnotationUtils.usePartParser(a));
apply(a.schema());
return this;
}
HttpPartSchemaBuilder apply(ResponseBody a) {
serializer(a.partSerializer());
- usePartSerializer(a.usePartSerializer() || a.partSerializer()
!= HttpPartSerializer.Null.class);
+ usePartSerializer(AnnotationUtils.usePartSerializer(a));
apply(a.schema());
return this;
}
@@ -284,7 +284,7 @@ public class HttpPartSchemaBuilder {
required(false);
allowEmptyValue(true);
serializer(a.partSerializer());
- usePartSerializer(a.usePartSerializer() || a.partSerializer()
!= HttpPartSerializer.Null.class);
+ usePartSerializer(AnnotationUtils.usePartSerializer(a));
apply(a.schema());
return this;
}
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 f5d1db8..c61c5ab 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
@@ -2157,6 +2157,36 @@ public final class ClassUtils {
}
/**
+ * Returns the simple name of a class.
+ *
+ * <p>
+ * Similar to {@link Class#getSimpleName()}, but includes the simple
name of an enclosing or declaring class.
+ *
+ * @param t The class to get the simple name on.
+ * @return The simple name of a class.
+ */
+ public static String getSimpleName(Type t) {
+ if (t instanceof Class)
+ return getSimpleName((Class<?>)t);
+ if (t instanceof ParameterizedType) {
+ StringBuilder sb = new StringBuilder();
+ ParameterizedType pt = (ParameterizedType)t;
+ sb.append(getSimpleName(pt.getRawType()));
+ sb.append("<");
+ boolean first = true;
+ for (Type t2 : pt.getActualTypeArguments()) {
+ if (! first)
+ sb.append(',');
+ first = false;
+ sb.append(getSimpleName(t2));
+ }
+ sb.append(">");
+ return sb.toString();
+ }
+ return null;
+ }
+
+ /**
* Returns <jk>true</jk> if the {@link #getAnnotation(Class, Method,
int)} returns a value.
*
* @param a The annotation to check for.
@@ -2180,14 +2210,14 @@ public final class ClassUtils {
}
/**
- * Returns <jk>true</jk> if the {@link #getAnnotation(Class, Class)}
returns a value.
+ * Returns <jk>true</jk> if the {@link #getAnnotation(Class, Type)}
returns a value.
*
* @param a The annotation to check for.
- * @param c The class to check.
- * @return <jk>true</jk> if the {@link #getAnnotation(Class, Class)}
returns a value.
+ * @param t The class to check.
+ * @return <jk>true</jk> if the {@link #getAnnotation(Class, Type)}
returns a value.
*/
- public static boolean hasAnnotation(Class<? extends Annotation> a,
Class<?> c) {
- return getAnnotation(a, c) != null;
+ public static boolean hasAnnotation(Class<? extends Annotation> a, Type
t) {
+ return getAnnotation(a, t) != null;
}
/**
@@ -2206,9 +2236,7 @@ public final class ClassUtils {
Type t = m.getGenericParameterTypes()[index];
if (Value.isType(t))
return getAnnotation(a, Value.getParameterType(t));
- if (t instanceof Class)
- return getAnnotation(a, (Class<?>)t);
- return null;
+ return getAnnotation(a, t);
}
/**
@@ -2229,10 +2257,10 @@ public final class ClassUtils {
if (a.isInstance(a2))
l.add((T)a2);
Type t = m.getGenericParameterTypes()[index];
- if (t instanceof Class)
- appendAnnotations(a, (Class<?>)t, l);
- else if (Value.isType(t))
+ if (Value.isType(t))
appendAnnotations(a, Value.getParameterType(t), l);
+ else
+ appendAnnotations(a, t, l);
return l;
}
@@ -2270,10 +2298,10 @@ public final class ClassUtils {
if (a.isInstance(a2))
l.add((T)a2);
Type t = m.getGenericReturnType();
- if (t instanceof Class)
- appendAnnotations(a, (Class<?>)t, l);
- else if (Value.isType(t))
+ if (Value.isType(t))
appendAnnotations(a, Value.getParameterType(t), l);
+ else
+ appendAnnotations(a, t, l);
return l;
}
@@ -2305,10 +2333,7 @@ public final class ClassUtils {
for (Annotation a2 : m.getAnnotations())
if (a.isInstance(a2))
return (T)a2;
- Type t = m.getGenericReturnType();
- if (t instanceof Class)
- return getAnnotation(a, (Class<?>)t);
- return null;
+ return getAnnotation(a, m.getGenericReturnType());
}
/**
@@ -2316,25 +2341,25 @@ public final class ClassUtils {
*
* @param <T> The annotation class type.
* @param a The annotation class.
- * @param c The annotated class.
+ * @param t The annotated class.
* @return The annotation, or <jk>null</jk> if not found.
*/
- public static <T extends Annotation> T getAnnotation(Class<T> a,
Class<?> c) {
- if (c == null)
- return null;
-
- T t = getDeclaredAnnotation(a, c);
- if (t != null)
- return t;
-
- t = getAnnotation(a, c.getSuperclass());
- if (t != null)
- return t;
-
- for (Class<?> c2 : c.getInterfaces()) {
- t = getAnnotation(a, c2);
- if (t != null)
- return t;
+ public static <T extends Annotation> T getAnnotation(Class<T> a, Type
t) {
+ Class<?> c = toClass(t);
+ if (c != null) {
+ T t2 = getDeclaredAnnotation(a, c);
+ if (t2 != null)
+ return t2;
+
+ t2 = getAnnotation(a, c.getSuperclass());
+ if (t2 != null)
+ return t2;
+
+ for (Class<?> c2 : c.getInterfaces()) {
+ t2 = getAnnotation(a, c2);
+ if (t2 != null)
+ return t2;
+ }
}
return null;
}
@@ -2348,14 +2373,16 @@ public final class ClassUtils {
*
* @param <T> The annotation class type.
* @param a The annotation class.
- * @param c The annotated class.
+ * @param t The annotated class.
* @return The annotation, or <jk>null</jk> if not found.
*/
@SuppressWarnings("unchecked")
- public static <T extends Annotation> T getDeclaredAnnotation(Class<T>
a, Class<?> c) {
- for (Annotation a2 : c.getDeclaredAnnotations())
- if (a2.annotationType() == a)
- return (T)a2;
+ public static <T extends Annotation> T getDeclaredAnnotation(Class<T>
a, Type t) {
+ Class<?> c = toClass(t);
+ if (c != null)
+ for (Annotation a2 : c.getDeclaredAnnotations())
+ if (a2.annotationType() == a)
+ return (T)a2;
return null;
}
@@ -2368,30 +2395,30 @@ public final class ClassUtils {
*
* @param <T> The annotation class type.
* @param a The annotation class type.
- * @param c The class being searched.
+ * @param t The class being searched.
* @return The found matches, or an empty array if annotation was not
found.
*/
- public static <T extends Annotation> List<T> getAnnotations(Class<T> a,
Class<?> c) {
+ public static <T extends Annotation> List<T> getAnnotations(Class<T> a,
Type t) {
List<T> l = new LinkedList<>();
- appendAnnotations(a, c, l);
+ appendAnnotations(a, t, l);
return l;
}
/**
- * Same as {@link #getAnnotations(Class, Class)} but returns the list
in parent-to-child order.
+ * Same as {@link #getAnnotations(Class, Type)} but returns the list in
parent-to-child order.
*
* @param a The annotation class type.
- * @param c The class being searched.
+ * @param t The class being searched.
* @return The found matches, or an empty array if annotation was not
found.
*/
- public static <T extends Annotation> List<T>
getAnnotationsParentFirst(Class<T> a, Class<?> c) {
- List<T> l = getAnnotations(a, c);
+ public static <T extends Annotation> List<T>
getAnnotationsParentFirst(Class<T> a, Type t) {
+ List<T> l = getAnnotations(a, t);
Collections.reverse(l);
return l;
}
/**
- * Same as {@link #getAnnotations(Class, Class)} except returns the
annotations as a map with the keys being the
+ * Same as {@link #getAnnotations(Class, Type)} except returns the
annotations as a map with the keys being the
* class on which the annotation was found.
*
* <p>
@@ -2399,39 +2426,40 @@ public final class ClassUtils {
*
* @param <T> The annotation class type.
* @param a The annotation class type.
- * @param c The class being searched.
+ * @param t The class being searched.
* @return The found matches, or an empty map if annotation was not
found.
*/
- public static <T extends Annotation> LinkedHashMap<Class<?>,T>
getAnnotationsMap(Class<T> a, Class<?> c) {
+ public static <T extends Annotation> LinkedHashMap<Class<?>,T>
getAnnotationsMap(Class<T> a, Type t) {
LinkedHashMap<Class<?>,T> m = new LinkedHashMap<>();
- findAnnotationsMap(a, c, m);
+ findAnnotationsMap(a, t, m);
return m;
}
/**
- * Same as {@link #getAnnotationsMap(Class, Class)} except returns
results in parent-to-child order.
+ * Same as {@link #getAnnotationsMap(Class, Type)} except returns
results in parent-to-child order.
*
* @param <T> The annotation class type.
* @param a The annotation class type.
- * @param c The class being searched.
+ * @param t The class being searched.
* @return The found matches, or an empty map if annotation was not
found.
*/
- public static <T extends Annotation> LinkedHashMap<Class<?>,T>
getAnnotationsMapParentFirst(Class<T> a, Class<?> c) {
- return CollectionUtils.reverse(getAnnotationsMap(a, c));
+ public static <T extends Annotation> LinkedHashMap<Class<?>,T>
getAnnotationsMapParentFirst(Class<T> a, Type t) {
+ return CollectionUtils.reverse(getAnnotationsMap(a, t));
}
- private static <T extends Annotation> void findAnnotationsMap(Class<T>
a, Class<?> c, Map<Class<?>,T> m) {
- if (c == null)
- return;
+ private static <T extends Annotation> void findAnnotationsMap(Class<T>
a, Type t, Map<Class<?>,T> m) {
+ Class<?> c = toClass(t);
+ if (c != null) {
- T t = getDeclaredAnnotation(a, c);
- if (t != null)
- m.put(c, t);
+ T t2 = getDeclaredAnnotation(a, c);
+ if (t2 != null)
+ m.put(c, t2);
- findAnnotationsMap(a, c.getSuperclass(), m);
+ findAnnotationsMap(a, c.getSuperclass(), m);
- for (Class<?> c2 : c.getInterfaces())
- findAnnotationsMap(a, c2, m);
+ for (Class<?> c2 : c.getInterfaces())
+ findAnnotationsMap(a, c2, m);
+ }
}
/**
@@ -2439,22 +2467,33 @@ public final class ClassUtils {
* list.
*
* @param a The annotation.
- * @param c The class.
+ * @param t The class.
* @param l The list of annotations.
*/
- public static <T extends Annotation> void appendAnnotations(Class<T> a,
Class<?> c, List<T> l) {
- if (c == null)
- return;
+ public static <T extends Annotation> void appendAnnotations(Class<T> a,
Type t, List<T> l) {
+ Class<?> c = toClass(t);
+ if (c != null) {
+ addIfNotNull(l, getDeclaredAnnotation(a, c));
- addIfNotNull(l, getDeclaredAnnotation(a, c));
+ if (c.getPackage() != null)
+ addIfNotNull(l,
c.getPackage().getAnnotation(a));
- if (c.getPackage() != null)
- addIfNotNull(l, c.getPackage().getAnnotation(a));
+ appendAnnotations(a, c.getSuperclass(), l);
- appendAnnotations(a, c.getSuperclass(), l);
+ for (Class<?> c2 : c.getInterfaces())
+ appendAnnotations(a, c2, l);
+ }
+ }
- for (Class<?> c2 : c.getInterfaces())
- appendAnnotations(a, c2, l);
+ private static Class<?> toClass(Type t) {
+ if (t instanceof Class)
+ return (Class<?>)t;
+ if (t instanceof ParameterizedType) {
+ ParameterizedType pt = (ParameterizedType)t;
+ // The raw type should always be a class (right?)
+ return (Class<?>)pt.getRawType();
+ }
+ return null;
}
/**
diff --git a/juneau-doc/src/main/javadoc/overview.html
b/juneau-doc/src/main/javadoc/overview.html
index 455ed03..b156911 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -313,7 +313,7 @@
<li><p class='new'><a class='doclink'
href='#juneau-rest-server.HttpPartAnnotations.Header'>@Header</a></p>
<li><p class='new'><a class='doclink'
href='#juneau-rest-server.HttpPartAnnotations.Path'>@Path</a></p>
<li><p class='new'><a class='doclink'
href='#juneau-rest-server.HttpPartAnnotations.RequestBean'>@RequestBean</a></p>
- <li><p class='todo'><a class='doclink'
href='#juneau-rest-server.HttpPartAnnotations.ResponseBody'>@ResponseBody</a></p>
+ <li><p class='new'><a class='doclink'
href='#juneau-rest-server.HttpPartAnnotations.ResponseBody'>@ResponseBody</a></p>
<li><p class='todo'><a class='doclink'
href='#juneau-rest-server.HttpPartAnnotations.ResponseHeader'>@ResponseHeader</a></p>
<li><p class='todo'><a class='doclink'
href='#juneau-rest-server.HttpPartAnnotations.ResponseStatus'>@ResponseStatus</a></p>
<li><p class='todo'><a class='doclink'
href='#juneau-rest-server.HttpPartAnnotations.Response'>@Response</a></p>
@@ -15615,28 +15615,42 @@ TODO(7.2.0)
<h4 class='topic new' onclick='toggle(this)'><a
href='#juneau-rest-server.HttpPartAnnotations.RequestBean'
id='juneau-rest-server.HttpPartAnnotations.RequestBean'>7.9.8 -
@RequestBean</a></h4>
<div class='topic'><!-- START: 7.9.8 -
juneau-rest-server.HttpPartAnnotations.RequestBean -->
<p>
- The {@link org.apache.juneau.http.annotation.RequestBean @RequestBean}
annotation can be applied to a parameter or parameter type of a
<ja>@RestMethod</ja>-annotated method
+ The {@link org.apache.juneau.http.annotation.RequestBean @RequestBean}
annotation can be applied to a parameter interface type of a
<ja>@RestMethod</ja>-annotated method
to identify it as an interface for retrieving HTTP parts through a bean
interface.
</p>
<h5 class='section'>Example:</h5>
<p class='bpcode w800'>
- <ja>@RestMethod</ja>(path=<js>"/mypath/{p1}/{p2}/*"</js>)
- <jk>public void</jk> myMethod(<ja>@RequestBean</ja> MyRequestBean rb)
{...}
+ <ja>@RestMethod</ja>(path=<js>"/pets/{petId}"</js>)
+ <jk>public void</jk> putPet(UpdatePet updatePet) {...}
- <jk>public interface</jk> MyRequestBean {
+ <ja>@RequestBean</ja>
+ <jk>public interface</jk> UpdatePet {
- <ja>@Path</ja> <jc>// Path variable name inferred from
getter.</jc>
- String getP1();
+ <ja>@Path</ja>
+ <jk>int</jk> getPetId();
- <ja>@Path</ja>(<js>"p2"</js>)
- String getX();
+ <ja>@Query</ja>(name=<js>"verbose"</js>)
+ <jk>boolean</jk> isDebug();
- <ja>@Path</ja>(<js>"/*"</js>)
- String getRemainder();
+ <ja>@Header</ja>(<js>"*"</js>)
+ Map<String,Object> getAllHeaders();
- <ja>@Query</ja>
- String getQ1();
+ <ja>@Body</ja>
+ Pet getPet();
+</p>
+<p>
+ The return types of the getters must be the supported parameter types
for the HTTP-part annotation used.
+ <br>Schema-based serialization and parsing is used just as if used as
individual parameter types.
+</p>
+<p>
+ It should be noted that the annotations used are the exact same used on
REST parameters and have all the
+ same feature support including automatic Swagger validation and
documentation.
+</p>
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+ <ja>@RequestBean</ja>
+ <jk>public interface</jk> RequestBean {
<jc>// Schema-based query parameter: Pipe-delimited lists of
comma-delimited lists of integers.</jc>
<ja>@Query</ja>(
@@ -15644,35 +15658,77 @@ TODO(7.2.0)
items=<ja>@Items</ja>(
items=<ja>@SubItems</ja>(
collectionFormat=<js>"csv"</js>
- type=<js>"integer"</js>
- )
+ type=<js>"integer"</js>,
+ minimum=1,
+ maximum=100
+ ),
+ maximumLength=10
)
)
- <jk>int</jk>[][] getQ3();
-
- <ja>@Header</ja>(<js>"*"</js>)
- Map<String,Object> getHeaders();
-</p>
-<p class='bpcode w800'>
- <jc>// Same as above but annotation defined on interface.</jc>
- <ja>@RestMethod</ja>(path=<js>"/mypath/{p1}/{p2}/*"</js>)
- <jk>public void</jk> myMethod(MyRequestBean rb) {...}
-
- <ja>@RequestBean</ja>
- <jk>public interface</jk> MyRequestBean {...}
-</p>
-<p>
- The return types of the getters must be the supported parameter types
for the HTTP-part annotation used.
- <br>Schema-based serialization and parsing is used just as if used as
individual parameter types.
+ <jk>int</jk>[][] getPipeCdlInts();
+ }
</p>
</div><!-- END: 7.9.8 - juneau-rest-server.HttpPartAnnotations.RequestBean -->
<!--
====================================================================================================
-->
-<h4 class='topic todo' onclick='toggle(this)'><a
href='#juneau-rest-server.HttpPartAnnotations.ResponseBody'
id='juneau-rest-server.HttpPartAnnotations.ResponseBody'>7.9.9 -
@ResponseBody</a></h4>
+<h4 class='topic new' onclick='toggle(this)'><a
href='#juneau-rest-server.HttpPartAnnotations.ResponseBody'
id='juneau-rest-server.HttpPartAnnotations.ResponseBody'>7.9.9 -
@ResponseBody</a></h4>
<div class='topic'><!-- START: 7.9.9 -
juneau-rest-server.HttpPartAnnotations.ResponseBody -->
<p>
+ The {@link org.apache.juneau.http.annotation.ResponseBody
@ResponseBody} annotation is used to identify a placeholder parameter
+ for an HTTP response.
</p>
+<ul class='doctree'>
+ <li class='ja'>{@link org.apache.juneau.http.annotation.ResponseBody
ResponseBody}
+ <ul>
+ <li class='jf'>{@link
org.apache.juneau.http.annotation.ResponseBody#api() api()} - Free-form Swagger
JSON.
+ <li class='jf'>{@link
org.apache.juneau.http.annotation.ResponseBody#example() example()} -
Serialized example.
+ <li class='jf'>{@link
org.apache.juneau.http.annotation.ResponseBody#examples() examples()} -
Serialized examples per media type.
+ <li class='jf'>{@link
org.apache.juneau.http.annotation.ResponseBody#partSerializer()
partSerializer()} - Override the part serializer.
+ <li class='jf'>{@link
org.apache.juneau.http.annotation.ResponseBody#schema() schema()} - Swagger
schema.
+ <li class='jf'>{@link
org.apache.juneau.http.annotation.ResponseBody#usePartSerializer()
usePartSerializer()} - Use the HTTP-Part serializer for serializing the body.
+ </ul>
+</ul>
+<p>
+ It can be used in the following locations:
+</p>
+<ul>
+ <li>Parameters on <ja>@RestMethod</ja>-annotated methods.
+ <li>Classes of parameters on <ja>@RestMethod</ja>-annotated methods.
+ <li><ja>@RestMethod</ja>-annotated methods.
+</ul>
+
+<h5 class='topic'>Parameters on @RestMethod-annotated methods</h5>
+<p>
+ When used on a method parameter, this annotation is used to identify a
placeholder {@link org.apache.juneau.Value}
+ object that can be used to return the body of the response.
+</p>
+<p class='bpcode w800'>
+ <ja>@RestMethod</ja>(path="/pet/{petId}")
+ <jk>public void</jk> getPet(<ja>@Path</ja>(<js>"petId"</js>)
<jk>int</jk> id, <ja>@ResponseBody</ja> Value<Pet> body) {
+ body.set(<jsm>getPet</jsm>(id));
+ }
+</p>
+<p>
+ The behavior is identical to the following:
+</p>
+<p class='bpcode w800'>
+ <ja>@RestMethod</ja>(path="/pet/{petId}")
+ <jk>public</jk> Pet getPet(<ja>@Path</ja>(<js>"petId"</js>)
<jk>int</jk> id) {
+ <jk>return</jk> <jsm>getPet</jsm>(id);
+ }
+</p>
+<p>
+ You may ask why you would use ever use this.
+ The answer is that it's possible to have your method returns something
else such as an HTTP response status
+ or header value.
+ This annotation allows you to set a response body when your method is
returning one of these.
+</p>
+
+<h5 class='topic'>Classes of parameters on @RestMethod-annotated methods</h5>
+
+
+<h5 class='topic'>@RestMethod-annotated methods</h5>
</div><!-- END: 7.9.9 - juneau-rest-server.HttpPartAnnotations.ResponseBody -->
<!--
====================================================================================================
-->
diff --git
a/juneau-doc/src/main/resources/Topics/02.juneau-marshall/10.Transforms/02.PerMediaTypePojoSwaps.html
b/juneau-doc/src/main/resources/Topics/02.juneau-marshall/10.Transforms/02.PerMediaTypePojoSwaps.html
index f0806b1..d0d071e 100644
---
a/juneau-doc/src/main/resources/Topics/02.juneau-marshall/10.Transforms/02.PerMediaTypePojoSwaps.html
+++
b/juneau-doc/src/main/resources/Topics/02.juneau-marshall/10.Transforms/02.PerMediaTypePojoSwaps.html
@@ -13,7 +13,7 @@
***************************************************************************************************************************/
-->
-Per-media-type PojoSwaps
+{new} Per-media-type PojoSwaps
<p>
Swaps can also be defined per-media-type.
@@ -89,3 +89,23 @@ Per-media-type PojoSwaps
}
}
</p>
+<p>
+ When multiple swaps match the same media type, a best-match algorithm
is applied to find the correct
+ swap to use.
+</p>
+<p>
+ In later sections we describe how annotations can be used to shorten
this syntax:
+</p>
+<p class='bpcode w800'>
+
<ja>@Swaps</ja>({MyJsonSwap.<jk>class</jk>,MyXmlSwap.<jk>class</jk>,MyOtherSwap.<jk>class</jk>})
+ <jk>public static class</jk> MyPojo {}
+
+ <ja>@Swap</ja>(mediaTypes=<js>"*/json"</js>)
+ <jk>public static class</jk> MyJsonSwap <jk>extends</jk>
PojoSwap<MyPojo,String> {...}
+
+ <ja>@Swap</ja>(mediaTypes=<js>"*/xml"</js>)
+ <jk>public static class</jk> MyXmlSwap <jk>extends</jk>
PojoSwap<MyPojo,String> {...}
+
+ <ja>@Swap</ja>(mediaTypes=<js>"*/*"</js>)
+ <jk>public static class</jk> MyOtherSwap <jk>extends</jk>
PojoSwap<MyPojo,String> {...}
+</p>>
\ No newline at end of file
diff --git
a/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/09.HttpPartAnnotations/08.RequestBean.html
b/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/09.HttpPartAnnotations/08.RequestBean.html
index 5bd004d..91c9ed7 100644
---
a/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/09.HttpPartAnnotations/08.RequestBean.html
+++
b/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/09.HttpPartAnnotations/08.RequestBean.html
@@ -16,28 +16,42 @@
{new} @RequestBean
<p>
- The {@link org.apache.juneau.http.annotation.RequestBean @RequestBean}
annotation can be applied to a parameter or parameter type of a
<ja>@RestMethod</ja>-annotated method
+ The {@link org.apache.juneau.http.annotation.RequestBean @RequestBean}
annotation can be applied to a parameter interface type of a
<ja>@RestMethod</ja>-annotated method
to identify it as an interface for retrieving HTTP parts through a bean
interface.
</p>
<h5 class='section'>Example:</h5>
<p class='bpcode w800'>
- <ja>@RestMethod</ja>(path=<js>"/mypath/{p1}/{p2}/*"</js>)
- <jk>public void</jk> myMethod(<ja>@RequestBean</ja> MyRequestBean rb)
{...}
+ <ja>@RestMethod</ja>(path=<js>"/pets/{petId}"</js>)
+ <jk>public void</jk> putPet(UpdatePet updatePet) {...}
- <jk>public interface</jk> MyRequestBean {
+ <ja>@RequestBean</ja>
+ <jk>public interface</jk> UpdatePet {
- <ja>@Path</ja> <jc>// Path variable name inferred from
getter.</jc>
- String getP1();
+ <ja>@Path</ja>
+ <jk>int</jk> getPetId();
- <ja>@Path</ja>(<js>"p2"</js>)
- String getX();
+ <ja>@Query</ja>(name=<js>"verbose"</js>)
+ <jk>boolean</jk> isDebug();
- <ja>@Path</ja>(<js>"/*"</js>)
- String getRemainder();
+ <ja>@Header</ja>(<js>"*"</js>)
+ Map<String,Object> getAllHeaders();
- <ja>@Query</ja>
- String getQ1();
+ <ja>@Body</ja>
+ Pet getPet();
+</p>
+<p>
+ The return types of the getters must be the supported parameter types
for the HTTP-part annotation used.
+ <br>Schema-based serialization and parsing is used just as if used as
individual parameter types.
+</p>
+<p>
+ It should be noted that the annotations used are the exact same used on
REST parameters and have all the
+ same feature support including automatic Swagger validation and
documentation.
+</p>
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+ <ja>@RequestBean</ja>
+ <jk>public interface</jk> RequestBean {
<jc>// Schema-based query parameter: Pipe-delimited lists of
comma-delimited lists of integers.</jc>
<ja>@Query</ja>(
@@ -45,24 +59,13 @@
items=<ja>@Items</ja>(
items=<ja>@SubItems</ja>(
collectionFormat=<js>"csv"</js>
- type=<js>"integer"</js>
- )
+ type=<js>"integer"</js>,
+ minimum=1,
+ maximum=100
+ ),
+ maximumLength=10
)
)
- <jk>int</jk>[][] getQ3();
-
- <ja>@Header</ja>(<js>"*"</js>)
- Map<String,Object> getHeaders();
-</p>
-<p class='bpcode w800'>
- <jc>// Same as above but annotation defined on interface.</jc>
- <ja>@RestMethod</ja>(path=<js>"/mypath/{p1}/{p2}/*"</js>)
- <jk>public void</jk> myMethod(MyRequestBean rb) {...}
-
- <ja>@RequestBean</ja>
- <jk>public interface</jk> MyRequestBean {...}
-</p>
-<p>
- The return types of the getters must be the supported parameter types
for the HTTP-part annotation used.
- <br>Schema-based serialization and parsing is used just as if used as
individual parameter types.
+ <jk>int</jk>[][] getPipeCdlInts();
+ }
</p>
diff --git
a/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/09.HttpPartAnnotations/09.ResponseBody.html
b/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/09.HttpPartAnnotations/09.ResponseBody.html
index 182ce0b..c54fb9f 100644
---
a/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/09.HttpPartAnnotations/09.ResponseBody.html
+++
b/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/09.HttpPartAnnotations/09.ResponseBody.html
@@ -16,4 +16,79 @@
{todo} @ResponseBody
<p>
+ The {@link org.apache.juneau.http.annotation.ResponseBody
@ResponseBody} annotation is used to identify a placeholder parameter
+ for an HTTP response.
</p>
+<ul class='doctree'>
+ <li class='ja'>{@link org.apache.juneau.http.annotation.ResponseBody
ResponseBody}
+ <ul>
+ <li class='jf'>{@link
org.apache.juneau.http.annotation.ResponseBody#api() api()} - Free-form Swagger
JSON.
+ <li class='jf'>{@link
org.apache.juneau.http.annotation.ResponseBody#example() example()} -
Serialized example.
+ <li class='jf'>{@link
org.apache.juneau.http.annotation.ResponseBody#examples() examples()} -
Serialized examples per media type.
+ <li class='jf'>{@link
org.apache.juneau.http.annotation.ResponseBody#partSerializer()
partSerializer()} - Override the part serializer.
+ <li class='jf'>{@link
org.apache.juneau.http.annotation.ResponseBody#schema() schema()} - Swagger
schema.
+ <li class='jf'>{@link
org.apache.juneau.http.annotation.ResponseBody#usePartSerializer()
usePartSerializer()} - Use the HTTP-Part serializer for serializing the body.
+ </ul>
+</ul>
+<p>
+ It can be used in the following locations:
+</p>
+<ul>
+ <li>Parameters on <ja>@RestMethod</ja>-annotated methods.
+ <li>Classes of parameters on <ja>@RestMethod</ja>-annotated methods.
+ <li><ja>@RestMethod</ja>-annotated methods.
+</ul>
+
+<h5 class='topic'>Parameters on @RestMethod-annotated methods</h5>
+<p>
+ When used on a method parameter, this annotation is used to identify a
placeholder {@link org.apache.juneau.Value}
+ object that can be used to return the body of the response.
+</p>
+<p class='bpcode w800'>
+ <ja>@RestMethod</ja>(path=<js>"/pet/{petId}"</js>)
+ <jk>public void</jk> getPet(<ja>@Path</ja>(<js>"petId"</js>)
<jk>int</jk> id, <ja>@ResponseBody</ja> Value<Pet> body) {
+ body.set(<jsm>getPet</jsm>(id));
+ }
+</p>
+<p>
+ The behavior is identical to the following:
+</p>
+<p class='bpcode w800'>
+ <ja>@RestMethod</ja>(path="/pet/{petId}")
+ <jk>public</jk> Pet getPet(<ja>@Path</ja>(<js>"petId"</js>)
<jk>int</jk> id) {
+ <jk>return</jk> <jsm>getPet</jsm>(id);
+ }
+</p>
+<p>
+ You may ask why you would use ever use this.
+ The answer is that it's possible to have your method returns something
else such as an HTTP response status
+ or header value.
+ This annotation allows you to set a response body when your method is
returning one of these.
+ <br>Also, the annotation allows you to define swagger validation and
documentation for your body.
+</p>
+
+<h5 class='topic'>Classes of parameters on @RestMethod-annotated methods</h5>
+<p>
+ The <ja>@ResponseBody</ja> annotation can also be applied to types.
+</p>
+<p class='bpcode w800'>
+ <ja>@RestMethod</ja>(path=<js>"/pet/{petId}"</js>)
+ <jk>public void</jk> getPet(<ja>@Path</ja>(<js>"petId"</js>)
<jk>int</jk> id, Value<Pet> body) {
+ body.set(<jsm>getPet</jsm>(id));
+ }
+</p>
+<p class='bpcode w800'>
+ <ja>@ResponseBody</ja>(
+ schema=<ja>@Schema</ja>(
+ description=<js>"Pet bean"</js>
+ )
+ )
+ <jk>public class</jk> Pet {...}
+</p>
+<p>
+ Note that this can often be cleaner-looking than usage on the Java
method parameter.
+</p>
+
+<h5 class='topic'>@RestMethod-annotated methods</h5>
+
+
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 3170923..1bed25a 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
@@ -379,27 +379,36 @@ final class SwaggerGenerator {
}
}
+ if (hasAnnotation(ResponseBody.class, m)) {
+ ObjectMap om = responses.getObjectMap("200",
true);
+ boolean usePS = false;
+ for (ResponseBody a :
getAnnotationsParentFirst(ResponseBody.class, m)) {
+ merge(om, a);
+ usePS |= usePartSerializer(a);
+ }
+ if (usePS && ! om.containsKey("schema"))
+ om.appendSkipEmpty("schema",
getSchema(om.getObjectMap("schema", true), m.getGenericReturnType()));
+ addXExamples(sm, om, "ok",
m.getGenericReturnType());
+ }
+
if (hasAnnotation(Response.class, m)) {
+ boolean usePS = false;
for (Response a :
getAnnotationsParentFirst(Response.class, m)) {
for (Integer code : getCodes(a, 200)) {
ObjectMap om =
responses.getObjectMap(String.valueOf(code), true);
merge(om, a);
+ usePS |= usePartSerializer(a);
+ }
+ }
+ if (usePS) {
+ for (String code : responses.keySet()) {
+ ObjectMap om =
responses.getObjectMap(code);
if (! om.containsKey("schema"))
om.appendSkipEmpty("schema", getSchema(om.getObjectMap("schema", true),
m.getGenericReturnType()));
}
}
}
- if (hasAnnotation(ResponseBody.class, m)) {
- ObjectMap om = responses.getObjectMap("200",
true);
- for (ResponseBody a :
getAnnotationsParentFirst(ResponseBody.class, m)) {
- merge(om, a);
- if (! om.containsKey("schema"))
- om.appendSkipEmpty("schema",
getSchema(om.getObjectMap("schema", true), m.getGenericReturnType()));
- }
- addXExamples(sm, om, "ok",
m.getGenericReturnType());
- }
-
// Finally, look for @ResponseHeader parameters defined
on method.
for (RestMethodParam mp :
context.getRestMethodParams(m)) {
@@ -414,24 +423,33 @@ final class SwaggerGenerator {
}
} else if (in == RESPONSE) {
+ boolean usePS = false;
for (Response a :
getAnnotationsParentFirst(Response.class, mp.method, mp.index)) {
for (Integer code : getCodes(a,
200)) {
ObjectMap response =
responses.getObjectMap(String.valueOf(code), true);
merge(response, a);
- if (!
response.containsKey("schema")) {
- Type type =
Value.getParameterType(mp.type);
- if (type !=
null)
-
response.appendSkipEmpty("schema", getSchema(response.getObjectMap("schema",
true), type));
+ usePS |=
usePartSerializer(a);
+ }
+ }
+ if (usePS) {
+ Type type =
Value.getParameterType(mp.type);
+ if (type != null) {
+ for (String code :
responses.keySet()) {
+ ObjectMap om =
responses.getObjectMap(code);
+ if (!
om.containsKey("schema"))
+
om.appendSkipEmpty("schema", getSchema(om.getObjectMap("schema", true), type));
}
}
}
} else if (in == RESPONSE_BODY) {
ObjectMap response =
responses.getObjectMap("200", true);
+ boolean usePS = false;
for (ResponseBody a :
getAnnotationsParentFirst(ResponseBody.class, mp.method, mp.index)) {
merge(response, a);
+ usePS |= usePartSerializer(a);
}
- if (! response.containsKey("schema")) {
+ if (usePS && !
response.containsKey("schema")) {
Type type =
Value.getParameterType(mp.type);
if (type != null)
response.appendSkipEmpty("schema", getSchema(response.getObjectMap("schema",
true), type));
diff --git
a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java
b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java
index 618bc6c..139c47c 100644
---
a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java
+++
b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/BasicRestInfoProviderTest.java
@@ -2196,7 +2196,7 @@ public class BasicRestInfoProviderTest {
@RestMethod(name=GET,path="/path/{foo}/responses/100")
public OE01x doFoo() {return null;}
}
- @Response(code=100)
+ @Response(code=100,usePartSerializer=true)
public static class OE01x extends Foo {}
@Test
diff --git
a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseAnnotationTest.java
b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseAnnotationTest.java
index 692bd1e..c2e6a59 100644
---
a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseAnnotationTest.java
+++
b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseAnnotationTest.java
@@ -659,7 +659,7 @@ public class ResponseAnnotationTest {
@RestMethod
public SB01 sb01b() {return null;}
- @Response
+ @Response(usePartSerializer=true)
public static class SB02 {
public String f1;
}
@@ -668,7 +668,7 @@ public class ResponseAnnotationTest {
@RestMethod
public SB02 sb02b() {return null;}
- @Response
+ @Response(usePartSerializer=true)
public static class SB03 extends LinkedList<String> {
private static final long serialVersionUID = 1L;
}
@@ -677,7 +677,7 @@ public class ResponseAnnotationTest {
@RestMethod
public SB03 sb03b() {return null;}
- @Response
+ @Response(usePartSerializer=true)
public static class SB04 {}
@RestMethod
public void sb04a(Value<SB04> b) {}
diff --git
a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseBodyAnnotationTest.java
b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseBodyAnnotationTest.java
new file mode 100644
index 0000000..0324663
--- /dev/null
+++
b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseBodyAnnotationTest.java
@@ -0,0 +1,452 @@
+//
***************************************************************************************************************************
+// * 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 static org.apache.juneau.testutils.TestUtils.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.dto.swagger.*;
+import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.httppart.*;
+import org.apache.juneau.json.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.utils.*;
+import org.junit.*;
+import org.junit.runners.*;
+
+/**
+ * Tests the @Response annotation.
+ */
+@SuppressWarnings({"javadoc","serial"})
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class ResponseBodyAnnotationTest {
+
+
//=================================================================================================================
+ // Setup
+
//=================================================================================================================
+
+ private static Swagger getSwagger(Object resource) {
+ try {
+ RestContext rc = RestContext.create(resource).build();
+ RestRequest req = rc.getCallHandler().createRequest(new
MockServletRequest());
+ RestInfoProvider ip = rc.getInfoProvider();
+ return ip.getSwagger(req);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+
+
//=================================================================================================================
+ // Basic tests
+
//=================================================================================================================
+
+
//-----------------------------------------------------------------------------------------------------------------
+ // Basic
+
//-----------------------------------------------------------------------------------------------------------------
+
+ @RestResource
+ public static class A {
+
+ @RestMethod
+ public void m01(@ResponseBody Value<A01> body) {
+ body.set(new A01());
+ }
+
+ @RestMethod
+ public void m02(Value<A02> body) {
+ body.set(new A02());
+ }
+
+ @RestMethod
+ @ResponseBody
+ public A01 m03() {
+ return new A01();
+ }
+
+ @RestMethod
+ public A02 m04() {
+ return new A02();
+ }
+ }
+
+ public static class A01 {
+ @Override
+ public String toString() {return "foo";}
+ }
+
+ @ResponseBody
+ public static class A02 {
+ @Override
+ public String toString() {return "foo";}
+ }
+
+ static MockRest a = MockRest.create(A.class);
+
+ @Test
+ public void a01_basic_onParameter() throws Exception {
+ a.get("/m01").execute().assertStatus(200).assertBody("foo");
+ }
+ @Test
+ public void a02_basic_onType() throws Exception {
+ a.get("/m02").execute().assertStatus(200).assertBody("foo");
+ }
+ @Test
+ public void a03_basic_onMethod() throws Exception {
+ a.get("/m03").execute().assertStatus(200).assertBody("foo");
+ }
+ @Test
+ public void a04_basic_onReturnedType() throws Exception {
+ a.get("/m04").execute().assertStatus(200).assertBody("foo");
+ }
+
+
//-----------------------------------------------------------------------------------------------------------------
+ // Basic swagger
+
//-----------------------------------------------------------------------------------------------------------------
+
+ @RestResource
+ public static class B {
+
+ @RestMethod
+ public void m01(@ResponseBody(schema=@Schema(description="b01",
collectionFormat="pipes")) Value<List<Integer>> body) {
+ body.set(AList.create(1,2));
+ }
+
+ @RestMethod
+ public void m02(Value<B01> body) {
+ body.set(new B01());
+ }
+
+ @RestMethod
+ @ResponseBody(schema=@Schema(description="b03",
collectionFormat="pipes"))
+ public List<Integer> m03() {
+ return AList.create(1,2);
+ }
+
+ @RestMethod
+ public B01 m04() {
+ return new B01();
+ }
+ }
+
+ @ResponseBody(schema=@Schema(description="b01",
collectionFormat="pipes"))
+ public static class B01 extends ArrayList<Integer> {
+ public B01() {
+ add(1);
+ add(2);
+ }
+ }
+
+ static MockRest b = MockRest.create(B.class);
+ static Swagger sb = getSwagger(new B());
+
+ @Test
+ public void b01a_basic_onParameter() throws Exception {
+ b.get("/m01").execute().assertStatus(200).assertBody("1|2");
+ }
+ @Test
+ public void b01b_basic_onParameter_swagger() throws Exception {
+ ResponseInfo ri = sb.getResponseInfo("/m01", "get", 200);
+
assertObjectEquals("{description:'OK',schema:{description:'b01',collectionFormat:'pipes'}}",
ri);
+ }
+ @Test
+ public void b02a_basic_onType() throws Exception {
+ b.get("/m02").execute().assertStatus(200).assertBody("1|2");
+ }
+ @Test
+ public void b02b_basic_onParameter_swagger() throws Exception {
+ ResponseInfo ri = sb.getResponseInfo("/m02", "get", 200);
+
assertObjectEquals("{description:'OK',schema:{description:'b01',collectionFormat:'pipes'}}",
ri);
+ }
+ @Test
+ public void b03a_basic_onMethod() throws Exception {
+ b.get("/m03").execute().assertStatus(200).assertBody("1|2");
+ }
+ @Test
+ public void b03b_basic_onParameter_swagger() throws Exception {
+ ResponseInfo ri = sb.getResponseInfo("/m03", "get", 200);
+
assertObjectEquals("{description:'OK',schema:{description:'b03',collectionFormat:'pipes'}}",
ri);
+ }
+ @Test
+ public void b04a_basic_onReturnedType() throws Exception {
+ b.get("/m04").execute().assertStatus(200).assertBody("1|2");
+ }
+ @Test
+ public void b04b_basic_onParameter_swagger() throws Exception {
+ ResponseInfo ri = sb.getResponseInfo("/m04", "get", 200);
+
assertObjectEquals("{description:'OK',schema:{description:'b01',collectionFormat:'pipes'}}",
ri);
+ }
+
+
//-----------------------------------------------------------------------------------------------------------------
+ // Test JSON Accept
+
//-----------------------------------------------------------------------------------------------------------------
+
+ @RestResource(serializers=SimpleJsonSerializer.class)
+ public static class C {
+
+ @RestMethod
+ public void m01(@ResponseBody Value<List<Integer>> body) {
+ body.set(AList.create(1,2));
+ }
+
+ @RestMethod
+ public void m02(Value<C01> body) {
+ body.set(new C01());
+ }
+
+ @RestMethod
+ @ResponseBody
+ public List<Integer> m03() {
+ return AList.create(1,2);
+ }
+
+ @RestMethod
+ public C01 m04() {
+ return new C01();
+ }
+ }
+
+ @ResponseBody
+ public static class C01 extends ArrayList<Integer> {
+ public C01() {
+ add(1);
+ add(2);
+ }
+ }
+
+ static MockRest c = MockRest.create(C.class);
+ static Swagger sc = getSwagger(new C());
+
+ @Test
+ public void c01a_basic_onParameter() throws Exception {
+
c.get("/m01").json().execute().assertStatus(200).assertBody("[1,2]");
+ }
+ @Test
+ public void c01b_basic_onParameter_swagger() throws Exception {
+ ResponseInfo ri = sc.getResponseInfo("/m01", "get", 200);
+ assertObjectEquals("{description:'OK'}", ri);
+ }
+ @Test
+ public void c02a_basic_onType() throws Exception {
+
c.get("/m02").json().execute().assertStatus(200).assertBody("[1,2]");
+ }
+ @Test
+ public void c02b_basic_onParameter_swagger() throws Exception {
+ ResponseInfo ri = sc.getResponseInfo("/m02", "get", 200);
+ assertObjectEquals("{description:'OK'}", ri);
+ }
+ @Test
+ public void c03a_basic_onMethod() throws Exception {
+
c.get("/m03").json().execute().assertStatus(200).assertBody("[1,2]");
+ }
+ @Test
+ public void c03b_basic_onParameter_swagger() throws Exception {
+ ResponseInfo ri = sc.getResponseInfo("/m03", "get", 200);
+ assertObjectEquals("{description:'OK'}", ri);
+ }
+ @Test
+ public void c04a_basic_onReturnedType() throws Exception {
+
c.get("/m04").json().execute().assertStatus(200).assertBody("[1,2]");
+ }
+ @Test
+ public void c04b_basic_onParameter_swagger() throws Exception {
+ ResponseInfo ri = sc.getResponseInfo("/m04", "get", 200);
+ assertObjectEquals("{description:'OK'}", ri);
+ }
+
+
+
//=================================================================================================================
+ // PartSerializers
+
//=================================================================================================================
+
+ public static class XPartSerializer implements HttpPartSerializer {
+ @Override
+ public HttpPartSerializerSession
createSession(SerializerSessionArgs args) {
+ return new HttpPartSerializerSession() {
+ @Override
+ public String serialize(HttpPartType partType,
HttpPartSchema schema, Object value) throws SerializeException,
SchemaValidationException {
+ return "x" + value + "x";
+ }
+ };
+ }
+
+ @Override
+ public String serialize(HttpPartType partType, HttpPartSchema
schema, Object value) throws SchemaValidationException, SerializeException {
+ return createSession(null).serialize(partType, schema,
value);
+ }
+
+ @Override
+ public String serialize(HttpPartSchema schema, Object value)
throws SchemaValidationException, SerializeException {
+ return createSession(null).serialize(null, schema,
value);
+ }
+ }
+
+
//-----------------------------------------------------------------------------------------------------------------
+ // @ResponseBody(usePartSerializer), partSerializer on class
+
//-----------------------------------------------------------------------------------------------------------------
+
+ @RestResource(partSerializer=XPartSerializer.class)
+ public static class D {
+
+ @RestMethod
+ public void m01(@ResponseBody(usePartSerializer=true)
Value<List<Integer>> body) {
+ body.set(AList.create(1,2));
+ }
+
+ @RestMethod
+ public void m02(Value<D01> body) {
+ body.set(new D01());
+ }
+
+ @RestMethod
+ @ResponseBody(usePartSerializer=true)
+ public List<Integer> m03() {
+ return AList.create(1,2);
+ }
+
+ @RestMethod
+ public D01 m04() {
+ return new D01();
+ }
+ }
+
+ @ResponseBody(usePartSerializer=true)
+ public static class D01 extends ArrayList<Integer> {
+ public D01() {
+ add(1);
+ add(2);
+ }
+ }
+
+ static MockRest d = MockRest.create(D.class);
+ static Swagger sd = getSwagger(new D());
+
+ @Test
+ public void d01a_basic_onParameter() throws Exception {
+ d.get("/m01").execute().assertStatus(200).assertBody("x[1,
2]x");
+ }
+ @Test
+ public void d01b_basic_onParameter_swagger() throws Exception {
+ ResponseInfo ri = sd.getResponseInfo("/m01", "get", 200);
+
assertObjectEquals("{description:'OK',schema:{type:'array',items:{type:'integer',format:'int32'}}}",
ri);
+ }
+ @Test
+ public void d02a_basic_onType() throws Exception {
+ d.get("/m02").execute().assertStatus(200).assertBody("x[1,
2]x");
+ }
+ @Test
+ public void d02b_basic_onParameter_swagger() throws Exception {
+ ResponseInfo ri = sd.getResponseInfo("/m02", "get", 200);
+
assertObjectEquals("{description:'OK',schema:{type:'array',items:{type:'integer',format:'int32'}}}",
ri);
+ }
+ @Test
+ public void d03a_basic_onMethod() throws Exception {
+ d.get("/m03").execute().assertStatus(200).assertBody("x[1,
2]x");
+ }
+ @Test
+ public void d03b_basic_onParameter_swagger() throws Exception {
+ ResponseInfo ri = sd.getResponseInfo("/m03", "get", 200);
+
assertObjectEquals("{description:'OK',schema:{type:'array',items:{type:'integer',format:'int32'}}}",
ri);
+ }
+ @Test
+ public void d04a_basic_onReturnedType() throws Exception {
+ d.get("/m04").execute().assertStatus(200).assertBody("x[1,
2]x");
+ }
+ @Test
+ public void d04b_basic_onParameter_swagger() throws Exception {
+ ResponseInfo ri = sd.getResponseInfo("/m04", "get", 200);
+
assertObjectEquals("{description:'OK',schema:{type:'array',items:{type:'integer',format:'int32'}}}",
ri);
+ }
+
+
//-----------------------------------------------------------------------------------------------------------------
+ // @ResponseBody(usePartSerializer), partSerializer on part.
+
//-----------------------------------------------------------------------------------------------------------------
+
+ @RestResource
+ public static class E {
+
+ @RestMethod
+ public void
m01(@ResponseBody(partSerializer=XPartSerializer.class) Value<List<Integer>>
body) {
+ body.set(AList.create(1,2));
+ }
+
+ @RestMethod
+ public void m02(Value<E01> body) {
+ body.set(new E01());
+ }
+
+ @RestMethod
+ @ResponseBody(partSerializer=XPartSerializer.class)
+ public List<Integer> m03() {
+ return AList.create(1,2);
+ }
+
+ @RestMethod
+ public E01 m04() {
+ return new E01();
+ }
+ }
+
+ @ResponseBody(partSerializer=XPartSerializer.class)
+ public static class E01 extends ArrayList<Integer> {
+ public E01() {
+ add(1);
+ add(2);
+ }
+ }
+
+ static MockRest e = MockRest.create(E.class);
+ static Swagger se = getSwagger(new E());
+
+ @Test
+ public void e01a_basic_onParameter() throws Exception {
+ e.get("/m01").execute().assertStatus(200).assertBody("x[1,
2]x");
+ }
+ @Test
+ public void e01b_basic_onParameter_swagger() throws Exception {
+ ResponseInfo ri = se.getResponseInfo("/m01", "get", 200);
+
assertObjectEquals("{description:'OK',schema:{type:'array',items:{type:'integer',format:'int32'}}}",
ri);
+ }
+ @Test
+ public void e02a_basic_onType() throws Exception {
+ e.get("/m02").execute().assertStatus(200).assertBody("x[1,
2]x");
+ }
+ @Test
+ public void e02b_basic_onParameter_swagger() throws Exception {
+ ResponseInfo ri = se.getResponseInfo("/m02", "get", 200);
+
assertObjectEquals("{description:'OK',schema:{type:'array',items:{type:'integer',format:'int32'}}}",
ri);
+ }
+ @Test
+ public void e03a_basic_onMethod() throws Exception {
+ e.get("/m03").execute().assertStatus(200).assertBody("x[1,
2]x");
+ }
+ @Test
+ public void e03b_basic_onParameter_swagger() throws Exception {
+ ResponseInfo ri = se.getResponseInfo("/m03", "get", 200);
+
assertObjectEquals("{description:'OK',schema:{type:'array',items:{type:'integer',format:'int32'}}}",
ri);
+ }
+ @Test
+ public void e04a_basic_onReturnedType() throws Exception {
+ e.get("/m04").execute().assertStatus(200).assertBody("x[1,
2]x");
+ }
+ @Test
+ public void e04b_basic_onParameter_swagger() throws Exception {
+ ResponseInfo ri = se.getResponseInfo("/m04", "get", 200);
+
assertObjectEquals("{description:'OK',schema:{type:'array',items:{type:'integer',format:'int32'}}}",
ri);
+ }
+
+}