update the 3.x branch with actual master
diff --git a/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyConnector.java b/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyConnector.java index 504fb0e..c2b881d 100644 --- a/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyConnector.java +++ b/connectors/jetty-connector/src/main/java11/org/glassfish/jersey/jetty/connector/JettyConnector.java
@@ -422,8 +422,8 @@ final AtomicBoolean callbackInvoked = new AtomicBoolean(false); final Throwable failure; try { - final CompletableFuture<ClientResponse> responseFuture = - new CompletableFuture<ClientResponse>().whenComplete( + final CompletableFuture<ClientResponse> responseFuture = new CompletableFuture<ClientResponse>(); + responseFuture.whenComplete( (clientResponse, throwable) -> { if (throwable != null && throwable instanceof CancellationException) { // take care of future cancellation
diff --git a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerFactory.java b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerFactory.java index 4eb458d..28d03d4 100644 --- a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerFactory.java +++ b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpServerFactory.java
@@ -194,6 +194,31 @@ /** * Create new {@link HttpServer} instance. * + * @param uri uri on which the {@link ApplicationHandler} will be deployed. Only first path + * segment will be used as context path, the rest will be ignored. + * @param config web application configuration. + * @param secure used for call {@link NetworkListener#setSecure(boolean)}. + * @param sslEngineConfigurator Ssl settings to be passed to {@link NetworkListener#setSSLEngineConfig}. + * @param parentContext DI provider specific context with application's registered bindings. + * @param start if set to false, server will not get started, this allows end users to set + * additional properties on the underlying listener. + * @return newly created {@code HttpServer}. + * @throws ProcessingException in case of any failure when creating a new {@code HttpServer} instance. + * @see GrizzlyHttpContainer + * @since 2.37 + */ + public static HttpServer createHttpServer(final URI uri, + final ResourceConfig config, + final boolean secure, + final SSLEngineConfigurator sslEngineConfigurator, + final Object parentContext, + final boolean start) { + return createHttpServer(uri, new GrizzlyHttpContainer(config, parentContext), secure, sslEngineConfigurator, start); + } + + /** + * Create new {@link HttpServer} instance. + * * @param uri uri on which the {@link ApplicationHandler} will be deployed. Only first path * segment will be used as context path, the rest will be ignored. * @param config web application configuration. @@ -212,6 +237,27 @@ /** * Create new {@link HttpServer} instance. * + * @param uri uri on which the {@link ApplicationHandler} will be deployed. Only first path + * segment will be used as context path, the rest will be ignored. + * @param config web application configuration. + * @param parentContext DI provider specific context with application's registered bindings. + * @param start if set to false, server will not get started, this allows end users to set + * additional properties on the underlying listener. + * @return newly created {@code HttpServer}. + * @throws ProcessingException in case of any failure when creating a new {@code HttpServer} instance. + * @see GrizzlyHttpContainer + * @since 2.37 + */ + public static HttpServer createHttpServer(final URI uri, + final ResourceConfig config, + final Object parentContext, + final boolean start) { + return createHttpServer(uri, new GrizzlyHttpContainer(config, parentContext), false, null, start); + } + + /** + * Create new {@link HttpServer} instance. + * * @param uri uri on which the {@link ApplicationHandler} will be deployed. Only first path * segment will be used as context path, the rest will be ignored. * @param handler {@link HttpHandler} instance.
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 94599f2..8780e32 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, 2021 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.TRUE)) { - return completionStageResponseType; + && request.resolveProperty(ServerProperties.UNWRAP_COMPLETION_STAGE_IN_WRITER_ENABLE, Boolean.FALSE)) { + return isCompletionStageResponseResponseType ? entityType : completionStageResponseType; } return invocableResponseType; }
diff --git a/tests/e2e-server/pom.xml b/tests/e2e-server/pom.xml index 51408e2..3500e13 100644 --- a/tests/e2e-server/pom.xml +++ b/tests/e2e-server/pom.xml
@@ -96,6 +96,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 50d4255..5e536e6 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, 2021 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 @@ -65,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 @@ -106,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(); @@ -215,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<>();