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 03729407a4..52d812fdd4 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 @@ public class ResourceMethodInvoker implements Endpoint, ResourceInfo { private final Type invocableResponseType; private final boolean canUseInvocableResponseType; private final boolean isCompletionStageResponseType; + private final boolean isCompletionStageResponseResponseType; // CompletionStage private final Type completionStageResponseType; private final ResourceMethodDispatcher dispatcher; private final Method resourceMethod; @@ -313,6 +314,8 @@ protected void configure() { && 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 void addNameBoundProviders( @@ -465,7 +468,7 @@ private Response invoke(final RequestProcessingContext context, final Object res 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 @@ private Response invoke(final RequestProcessingContext context, final Object res 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 2650a3d27e..18cd641092 100644 --- a/tests/e2e-server/pom.xml +++ b/tests/e2e-server/pom.xml @@ -100,6 +100,11 @@ jersey-media-json-processing test + + org.glassfish.jersey.media + jersey-media-json-binding + test + org.glassfish.jersey.media jersey-media-json-gson 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 cf7ade3d68..fb4eafcb68 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 @@ public class CompletionStageTest extends JerseyTest { @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 @@ -104,6 +106,14 @@ public void testGetCompletedAsync() { assertThat(response.readEntity(String.class), is(ENTITY)); } + @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(); @@ -213,6 +223,14 @@ public CompletionStage getCompletedAsync() { return cs; } + @GET + @Path("/completedAsyncResponse") + public CompletionStage getCompletedAsyncResponse() { + CompletableFuture cs = new CompletableFuture<>(); + delaySubmit(() -> cs.complete(Response.ok().entity(Collections.singletonList(ENTITY)).build())); + return cs; + } + @GET @Path("/exception400Async") public CompletionStage getException400Async() {