diff --git a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/Reader.java b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/Reader.java index c15689ca92..1b0bcbcfe5 100644 --- a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/Reader.java +++ b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/Reader.java @@ -69,6 +69,7 @@ import java.util.Optional; import java.util.Set; import java.util.TreeSet; +import java.util.concurrent.CompletionStage; import java.util.stream.Collectors; public class Reader implements OpenApiReader { @@ -1071,7 +1072,7 @@ protected Operation parseMethod( Type returnType = method.getGenericReturnType(); if (annotatedMethod != null && annotatedMethod.getType() != null) { - returnType = annotatedMethod.getType(); + returnType = extractTypeFromMethod(annotatedMethod); } final Class subResource = getSubResourceWithJaxRsSubresourceLocatorSpecs(method); @@ -1133,6 +1134,14 @@ protected Operation parseMethod( return operation; } + private Type extractTypeFromMethod(AnnotatedMethod annotatedMethod) { + if(CompletionStage.class.isAssignableFrom(annotatedMethod.getType().getRawClass())) { + // CompletionStage's 1st generic type is the real return type. + return annotatedMethod.getType().getBindings().getBoundType(0); + } + return annotatedMethod.getType(); + } + protected Content resolveEmptyContent(Produces classProduces, Produces methodProduces) { Content content = new Content(); MediaType mediaType = new MediaType(); diff --git a/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/ReaderTest.java b/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/ReaderTest.java index 742141b118..da7c6c1b28 100644 --- a/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/ReaderTest.java +++ b/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/ReaderTest.java @@ -125,7 +125,10 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.stream.Collectors; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; @@ -717,6 +720,36 @@ public void test1(A a) { } } + @Test + public void testClassWithCompletableFuture() { + Reader reader = new Reader(new OpenAPI()); + OpenAPI openAPI = reader.read(ClassWithCompletableFuture.class); + assertNotNull(openAPI); + + assertEquals( + openAPI.getPaths() + .get("/myApi") + .getGet() + .getResponses() + .get("default") + .getContent() + .get("application/json") + .getSchema() + .get$ref(), + "#/components/schemas/Ret" + ); + } + + static class ClassWithCompletableFuture { + @Path("/myApi") + @Produces("application/json") + @Consumes("application/json") + @GET + public CompletableFuture myApi(A a) { + return CompletableFuture.completedFuture(new Ret()); + } + } + @Test(description = "test resource with array in response content") public void test2497() { Reader reader = new Reader(new OpenAPI());