Support CompletionStage<Response> Signed-off-by: jansupol <jan.supol@oracle.com>
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/model/ResourceMethodInvoker.java b/core-server/src/main/java/org/glassfish/jersey/server/model/ResourceMethodInvoker.java index 0372940..52d812f 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/model/ResourceMethodInvoker.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/model/ResourceMethodInvoker.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2022 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -85,6 +85,7 @@ private final Type invocableResponseType; private final boolean canUseInvocableResponseType; private final boolean isCompletionStageResponseType; + private final boolean isCompletionStageResponseResponseType; // CompletionStage<Response> private final Type completionStageResponseType; private final ResourceMethodDispatcher dispatcher; private final Method resourceMethod; @@ -313,6 +314,8 @@ && CompletionStage.class.isAssignableFrom((Class<?>) ((ParameterizedType) invocableResponseType).getRawType()); this.completionStageResponseType = isCompletionStageResponseType ? ((ParameterizedType) invocableResponseType).getActualTypeArguments()[0] : null; + this.isCompletionStageResponseResponseType = Class.class.isInstance(completionStageResponseType) + && Response.class.isAssignableFrom((Class<?>) completionStageResponseType); } private <T> void addNameBoundProviders( @@ -465,7 +468,7 @@ if (canUseInvocableResponseType && response.hasEntity() && !(response.getEntityType() instanceof ParameterizedType)) { - response.setEntityType(unwrapInvocableResponseType(context.request())); + response.setEntityType(unwrapInvocableResponseType(context.request(), response.getEntityType())); } return response; @@ -484,10 +487,10 @@ return jaxrsResponse; } - private Type unwrapInvocableResponseType(ContainerRequest request) { + private Type unwrapInvocableResponseType(ContainerRequest request, Type entityType) { if (isCompletionStageResponseType && request.resolveProperty(ServerProperties.UNWRAP_COMPLETION_STAGE_IN_WRITER_ENABLE, Boolean.FALSE)) { - return completionStageResponseType; + return isCompletionStageResponseResponseType ? entityType : completionStageResponseType; } return invocableResponseType; }
diff --git a/tests/e2e-server/pom.xml b/tests/e2e-server/pom.xml index 2650a3d..18cd641 100644 --- a/tests/e2e-server/pom.xml +++ b/tests/e2e-server/pom.xml
@@ -102,6 +102,11 @@ </dependency> <dependency> <groupId>org.glassfish.jersey.media</groupId> + <artifactId>jersey-media-json-binding</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-json-gson</artifactId> <scope>test</scope> </dependency>
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/CompletionStageTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/CompletionStageTest.java index cf7ade3..fb4eafc 100644 --- a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/CompletionStageTest.java +++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/CompletionStageTest.java
@@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -18,6 +18,7 @@ import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.ServerRuntime; import org.glassfish.jersey.test.JerseyTest; import org.junit.Test; @@ -64,7 +65,8 @@ @Override protected Application configure() { - return new ResourceConfig(CompletionStageResource.class, DataBeanWriter.class); + return new ResourceConfig(CompletionStageResource.class, DataBeanWriter.class) + .property(ServerProperties.UNWRAP_COMPLETION_STAGE_IN_WRITER_ENABLE, Boolean.TRUE); } @Test @@ -105,6 +107,14 @@ } @Test + public void testGetCompletedAsyncResponse() { + Response response = target("cs/completedAsyncResponse").request().get(); + + assertThat(response.getStatus(), is(200)); + assertThat(response.readEntity(List.class).get(0), is(ENTITY)); + } + + @Test public void testGetException400Async() { Response response = target("cs/exception400Async").request().get(); @@ -214,6 +224,14 @@ } @GET + @Path("/completedAsyncResponse") + public CompletionStage<Response> getCompletedAsyncResponse() { + CompletableFuture<Response> cs = new CompletableFuture<>(); + delaySubmit(() -> cs.complete(Response.ok().entity(Collections.singletonList(ENTITY)).build())); + return cs; + } + + @GET @Path("/exception400Async") public CompletionStage<String> getException400Async() { CompletableFuture<String> cs = new CompletableFuture<>();