merge of the actual 3.0 into the 3.1
diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/JerseyClientHandler.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/JerseyClientHandler.java
index adf8e03..e9d55c1 100644
--- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/JerseyClientHandler.java
+++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/JerseyClientHandler.java
@@ -18,7 +18,6 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
-import java.io.InputStream;
import java.net.URI;
import java.util.Iterator;
import java.util.List;
@@ -48,7 +47,6 @@
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpResponse;
-import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.timeout.IdleStateEvent;
import org.glassfish.jersey.uri.internal.JerseyUriBuilder;
@@ -146,7 +144,21 @@
ClientRequest newReq = new ClientRequest(jerseyRequest);
newReq.setUri(newUri);
restrictRedirectRequest(newReq, cr);
- connector.execute(newReq, redirectUriHistory, responseAvailable);
+
+ final NettyConnector newConnector = new NettyConnector(newReq.getClient());
+ newConnector.execute(newReq, redirectUriHistory, new CompletableFuture<ClientResponse>() {
+ @Override
+ public boolean complete(ClientResponse value) {
+ newConnector.close();
+ return responseAvailable.complete(value);
+ }
+
+ @Override
+ public boolean completeExceptionally(Throwable ex) {
+ newConnector.close();
+ return responseAvailable.completeExceptionally(ex);
+ }
+ });
}
} catch (IllegalArgumentException e) {
responseAvailable.completeExceptionally(
diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java
index 4544157..ebdfda4 100644
--- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java
+++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java
@@ -416,11 +416,7 @@
// headers
if (!jerseyRequest.hasEntity()) {
setHeaders(jerseyRequest, nettyRequest.headers(), false);
-
- // host header - http 1.1
- if (!nettyRequest.headers().contains(HttpHeaderNames.HOST)) {
- nettyRequest.headers().add(HttpHeaderNames.HOST, jerseyRequest.getUri().getHost());
- }
+ setHostHeader(jerseyRequest, nettyRequest);
}
if (jerseyRequest.hasEntity()) {
@@ -468,9 +464,7 @@
@Override
public OutputStream getOutputStream(int contentLength) throws IOException {
replaceHeaders(jerseyRequest, nettyRequest.headers()); // WriterInterceptor changes
- if (!nettyRequest.headers().contains(HttpHeaderNames.HOST)) {
- nettyRequest.headers().add(HttpHeaderNames.HOST, jerseyRequest.getUri().getHost());
- }
+ setHostHeader(jerseyRequest, nettyRequest);
headersSet.countDown();
return entityWriter.getOutputStream();
@@ -620,4 +614,18 @@
private static boolean additionalProxyHeadersToKeep(String key) {
return key.length() > 2 && (key.charAt(0) == 'x' || key.charAt(0) == 'X') && (key.charAt(1) == '-');
}
+
+ private static void setHostHeader(ClientRequest jerseyRequest, HttpRequest nettyRequest) {
+ // host header - http 1.1
+ if (!nettyRequest.headers().contains(HttpHeaderNames.HOST)) {
+ int requestPort = jerseyRequest.getUri().getPort();
+ final String hostHeader;
+ if (requestPort != 80 && requestPort != 443) {
+ hostHeader = jerseyRequest.getUri().getHost() + ":" + requestPort;
+ } else {
+ hostHeader = jerseyRequest.getUri().getHost();
+ }
+ nettyRequest.headers().add(HttpHeaderNames.HOST, hostHeader);
+ }
+ }
}
diff --git a/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/FollowRedirectsTest.java b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/FollowRedirectsTest.java
index 3a1cf69..d63b904 100644
--- a/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/FollowRedirectsTest.java
+++ b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/FollowRedirectsTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2024 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
@@ -24,16 +24,20 @@
import java.util.logging.Logger;
import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.ProcessingException;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
+import org.glassfish.jersey.client.RequestEntityProcessing;
import org.glassfish.jersey.logging.LoggingFeature;
import org.glassfish.jersey.netty.connector.internal.RedirectException;
import org.glassfish.jersey.server.ResourceConfig;
@@ -60,6 +64,11 @@
return "GET";
}
+ @POST
+ public String post() {
+ return "POST";
+ }
+
@GET
@Path("redirect")
public Response redirect() {
@@ -77,6 +86,12 @@
public Response redirect2() {
return Response.seeOther(URI.create(TEST_URL_REF.get() + "/redirect")).build();
}
+
+ @POST
+ @Path("status307")
+ public Response status307() {
+ return Response.temporaryRedirect(URI.create(TEST_URL_REF.get())).build();
+ }
}
@Override
@@ -169,4 +184,15 @@
assertEquals(200, r.getStatus());
assertEquals("GET", r.readEntity(String.class));
}
+
+ @Test
+ public void testRedirect307PostBuffered() {
+ try (Response response = target("test/status307")
+ .property(ClientProperties.FOLLOW_REDIRECTS, true)
+ .property(ClientProperties.REQUEST_ENTITY_PROCESSING, RequestEntityProcessing.BUFFERED)
+ .request().post(Entity.entity("Something", MediaType.TEXT_PLAIN_TYPE))) {
+ assertEquals(200, response.getStatus());
+ assertEquals("POST", response.readEntity(String.class));
+ }
+ }
}
diff --git a/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/HostHeaderTest.java b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/HostHeaderTest.java
new file mode 100644
index 0000000..a456acd
--- /dev/null
+++ b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/HostHeaderTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2024 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
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.netty.connector;
+
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.Test;
+
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.HttpHeaders;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+
+public class HostHeaderTest extends JerseyTest {
+
+ private static final String HTTP_HEADER_NAME = "HTTP_PORT_INT";
+
+ @Path("/")
+ public static class HostHeaderTestEchoResource {
+
+ @POST
+ public String post(@Context HttpHeaders headers) {
+ return get(headers);
+ }
+
+ @GET
+ public String get(@Context HttpHeaders headers) {
+ String sPort = headers.getHeaderString(HTTP_HEADER_NAME);
+ String hostPort = headers.getHeaderString(HttpHeaders.HOST);
+ int indexColon = hostPort.indexOf(':');
+ if (indexColon != -1) {
+ hostPort = hostPort.substring(indexColon + 1);
+ }
+ if (sPort.equals(hostPort.trim())) {
+ return GET.class.getName();
+ } else {
+ return "Expected port " + sPort + " but found " + hostPort;
+ }
+ }
+ }
+
+ @Override
+ protected Application configure() {
+ return new ResourceConfig(HostHeaderTestEchoResource.class);
+ }
+
+ @Test
+ public void testHostHeaderAndPort() {
+ int port = getPort();
+ ClientConfig config = new ClientConfig();
+ config.connectorProvider(new NettyConnectorProvider());
+ try (Response response = ClientBuilder.newClient(config).target(target().getUri())
+ .request()
+ .header(HTTP_HEADER_NAME, port)
+ .get()) {
+ MatcherAssert.assertThat(response.getStatus(), Matchers.is(200));
+ MatcherAssert.assertThat(response.readEntity(String.class), Matchers.is(GET.class.getName()));
+ }
+ }
+
+ @Test
+ public void testHostHeaderAndPortAfterRemovedFromFilter() {
+ int port = getPort();
+ ClientConfig config = new ClientConfig();
+ config.connectorProvider(new NettyConnectorProvider());
+ try (Response response = ClientBuilder.newClient(config)
+ .target(target().getUri())
+ .request()
+ .header(HTTP_HEADER_NAME, port)
+ .post(Entity.entity("xxx", MediaType.TEXT_PLAIN_TYPE))) {
+ MatcherAssert.assertThat(response.getStatus(), Matchers.is(200));
+ MatcherAssert.assertThat(response.readEntity(String.class), Matchers.is(GET.class.getName()));
+ }
+ }
+
+}
diff --git a/core-common/src/main/java/org/glassfish/jersey/innate/io/InputStreamWrapper.java b/core-common/src/main/java/org/glassfish/jersey/innate/io/InputStreamWrapper.java
index c2109fe..abcee6b 100644
--- a/core-common/src/main/java/org/glassfish/jersey/innate/io/InputStreamWrapper.java
+++ b/core-common/src/main/java/org/glassfish/jersey/innate/io/InputStreamWrapper.java
@@ -18,6 +18,7 @@
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
/**
* Generic wrapper template for InputStream.
@@ -55,6 +56,22 @@
}
@Override
+ public byte[] readAllBytes() throws IOException {
+ return getWrappedIOE().readAllBytes();
+ }
+
+ @Override
+ public int readNBytes(byte[] b, int off, int len) throws IOException {
+ return getWrappedIOE().readNBytes(b, off, len);
+ }
+
+ @Override
+ public long transferTo(OutputStream out) throws IOException {
+ return getWrappedIOE().transferTo(out);
+ }
+
+
+ @Override
public long skip(long n) throws IOException {
return getWrappedIOE().skip(n);
}
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/inject/ParamConverters.java b/core-common/src/main/java/org/glassfish/jersey/internal/inject/ParamConverters.java
index 5798695..aafb278 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/inject/ParamConverters.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/inject/ParamConverters.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018 Payara Foundation and/or its affiliates.
*
* This program and the accompanying materials are made available under the
@@ -125,7 +125,7 @@
@Singleton
public static class StringConstructor extends ParamConverterCompliance implements ParamConverterProvider {
- private StringConstructor(boolean canReturnNull) {
+ protected StringConstructor(boolean canReturnNull) {
super(canReturnNull);
}
@@ -154,7 +154,7 @@
@Singleton
public static class TypeValueOf extends ParamConverterCompliance implements ParamConverterProvider {
- private TypeValueOf(boolean canReturnNull) {
+ protected TypeValueOf(boolean canReturnNull) {
super(canReturnNull);
}
@@ -182,7 +182,7 @@
@Singleton
public static class TypeFromString extends ParamConverterCompliance implements ParamConverterProvider {
- private TypeFromString(boolean canReturnNull) {
+ protected TypeFromString(boolean canReturnNull) {
super(canReturnNull);
}
@@ -210,7 +210,7 @@
@Singleton
public static class TypeFromStringEnum extends TypeFromString {
- private TypeFromStringEnum(boolean canReturnNull) {
+ protected TypeFromStringEnum(boolean canReturnNull) {
super(canReturnNull);
}
@@ -225,7 +225,7 @@
@Singleton
public static class CharacterProvider extends ParamConverterCompliance implements ParamConverterProvider {
- private CharacterProvider(boolean canReturnNull) {
+ protected CharacterProvider(boolean canReturnNull) {
super(canReturnNull);
}
@@ -270,7 +270,7 @@
@Singleton
public static class DateProvider extends ParamConverterCompliance implements ParamConverterProvider {
- private DateProvider(boolean canReturnNull) {
+ protected DateProvider(boolean canReturnNull) {
super(canReturnNull);
}
@@ -346,7 +346,7 @@
// Delegates to this provider when the type of Optional is extracted.
private final InjectionManager manager;
- public OptionalCustomProvider(InjectionManager manager, boolean canReturnNull) {
+ protected OptionalCustomProvider(InjectionManager manager, boolean canReturnNull) {
super(canReturnNull);
this.manager = manager;
}
@@ -402,6 +402,8 @@
@Singleton
public static class OptionalProvider implements ParamConverterProvider {
+ protected OptionalProvider() {}
+
@Override
public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
final Optionals optionals = Optionals.getOptional(rawType);
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/EntityInputStream.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/EntityInputStream.java
index f94d5fd..2610e17 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/EntityInputStream.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/EntityInputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 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
@@ -22,6 +22,7 @@
import jakarta.ws.rs.ProcessingException;
+import org.glassfish.jersey.innate.io.InputStreamWrapper;
import org.glassfish.jersey.internal.LocalizationMessages;
/**
@@ -33,7 +34,7 @@
*
* @author Marek Potociar
*/
-public class EntityInputStream extends InputStream {
+public class EntityInputStream extends InputStreamWrapper {
private InputStream input;
private boolean closed = false;
@@ -64,40 +65,6 @@
this.input = input;
}
- @Override
- public int read() throws IOException {
- return input.read();
- }
-
- @Override
- public int read(byte[] b) throws IOException {
- return input.read(b);
- }
-
- @Override
- public int read(byte[] b, int off, int len) throws IOException {
- return input.read(b, off, len);
- }
-
- @Override
- public long skip(long n) throws IOException {
- return input.skip(n);
- }
-
- @Override
- public int available() throws IOException {
- return input.available();
- }
-
- @Override
- public void mark(int readLimit) {
- input.mark(readLimit);
- }
-
- @Override
- public boolean markSupported() {
- return input.markSupported();
- }
/**
* {@inheritDoc}
@@ -232,4 +199,9 @@
public final void setWrappedStream(InputStream wrapped) {
input = wrapped;
}
+
+ @Override
+ protected InputStream getWrapped() {
+ return input;
+ }
}
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundJaxrsResponse.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundJaxrsResponse.java
index 4db8b21..87fc281 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundJaxrsResponse.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundJaxrsResponse.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 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
@@ -26,6 +26,8 @@
import java.util.Date;
import java.util.HashSet;
import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
@@ -200,7 +202,12 @@
@Override
public void close() throws ProcessingException {
closed = true;
- context.close();
+ try {
+ context.close();
+ } catch (Exception e) {
+ // Just log the exception
+ Logger.getLogger(OutboundJaxrsResponse.class.getName()).log(Level.FINE, e.getMessage(), e);
+ }
if (buffered) {
// release buffer
context.setEntity(null);
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundMessageContext.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundMessageContext.java
index b1b7745..ceb1540 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundMessageContext.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundMessageContext.java
@@ -18,6 +18,7 @@
import java.io.IOException;
import java.io.OutputStream;
+import java.io.UncheckedIOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.ArrayList;
@@ -27,8 +28,6 @@
import java.util.Locale;
import java.util.Set;
import java.util.function.Function;
-import java.util.logging.Level;
-import java.util.logging.Logger;
import java.util.stream.Collectors;
import jakarta.ws.rs.core.Configuration;
@@ -557,6 +556,7 @@
/**
* Closes the context. Flushes and closes the entity stream.
+ * @throws UncheckedIOException if IO errors
*/
public void close() {
if (hasEntity()) {
@@ -567,11 +567,7 @@
}
es.close();
} catch (IOException e) {
- // Happens when the client closed connection before receiving the full response.
- // This is OK and not interesting in the vast majority of the cases
- // hence the log level set to FINE to make sure it does not flood the log unnecessarily
- // (especially for clients disconnecting from SSE listening, which is very common).
- Logger.getLogger(OutboundMessageContext.class.getName()).log(Level.FINE, e.getMessage(), e);
+ throw new UncheckedIOException(e);
} finally {
// In case some of the output stream wrapper does not delegate close() call we
// close the root stream manually to make sure it commits the data.
@@ -579,8 +575,7 @@
try {
committingOutputStream.close();
} catch (IOException e) {
- // Just log the exception
- Logger.getLogger(OutboundMessageContext.class.getName()).log(Level.FINE, e.getMessage(), e);
+ throw new UncheckedIOException(e);
}
}
}
diff --git a/core-common/src/main/java/org/glassfish/jersey/model/Parameter.java b/core-common/src/main/java/org/glassfish/jersey/model/Parameter.java
index 4f7af42..4183568 100644
--- a/core-common/src/main/java/org/glassfish/jersey/model/Parameter.java
+++ b/core-common/src/main/java/org/glassfish/jersey/model/Parameter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2024 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
@@ -446,14 +446,20 @@
parameterClass);
}
-
private static String getValue(Annotation a) {
try {
- Method m = a.annotationType().getMethod("value");
- if (m.getReturnType() != String.class) {
- return null;
+ Method[] methods = a.annotationType().getMethods();
+ for (Method method : methods) {
+ if ("value".equals(method.getName())) {
+ if (method.getReturnType() != String.class) {
+ return null;
+ } else {
+ return (String) method.invoke(a);
+ }
+ }
}
- return (String) m.invoke(a);
+ LOGGER.log(Level.FINER, () ->
+ String.format("Unable to get the %s annotation value property", a.getClass().getName()));
} catch (Exception ex) {
if (LOGGER.isLoggable(Level.FINER)) {
LOGGER.log(Level.FINER,
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ContainerResponse.java b/core-server/src/main/java/org/glassfish/jersey/server/ContainerResponse.java
index bd7f7a3..a44e60e 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/ContainerResponse.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/ContainerResponse.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 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
@@ -26,6 +26,8 @@
import java.net.URI;
import java.util.Date;
import java.util.Locale;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import java.util.Map;
import java.util.Set;
@@ -400,9 +402,14 @@
public void close() {
if (!closed) {
closed = true;
- messageContext.close();
- requestContext.getResponseWriter().commit();
- requestContext.setWorkers(null);
+ try {
+ messageContext.close();
+ requestContext.setWorkers(null);
+ requestContext.getResponseWriter().commit();
+ } catch (Exception e) {
+ Logger.getLogger(ContainerResponse.class.getName()).log(Level.FINE, e.getMessage(), e);
+ requestContext.getResponseWriter().failure(e);
+ }
}
}
diff --git a/docs/src/main/docbook/media.xml b/docs/src/main/docbook/media.xml
index 34d2a7d..f27d2f0 100644
--- a/docs/src/main/docbook/media.xml
+++ b/docs/src/main/docbook/media.xml
@@ -1129,7 +1129,7 @@
public class JsonbContextResolver implements ContextResolver<Jsonb> {
@Override
- public Jsonb getContext(Class>?< type) {
+ public Jsonb getContext(Class<?> type) {
JsonbConfig config = new JsonbConfig();
// configure JsonbConfig
...
diff --git a/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/DisposableSupplierTest.java b/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/DisposableSupplierTest.java
index 6bade9b..10eec31 100644
--- a/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/DisposableSupplierTest.java
+++ b/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/DisposableSupplierTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2024 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
@@ -17,6 +17,8 @@
package org.glassfish.jersey.inject.cdi.se;
import java.lang.reflect.Type;
+import java.util.HashSet;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
@@ -368,9 +370,17 @@
// All instances should be the same because they are request scoped.
ComposedObject instance = injectionManager.getInstance(ComposedObject.class);
- assertEquals("1", instance.getFirst());
- assertEquals("2", instance.getSecond());
- assertEquals("3", instance.getThird());
+ Set<String> set1 = new HashSet<String>() {{
+ add("1");
+ add("2");
+ add("3");
+ }};
+ Set<String> set2 = new HashSet<String>() {{
+ add(instance.getFirst().toString());
+ add(instance.getSecond().toString());
+ add(instance.getThird().toString());
+ }};
+ assertEquals(set1, set2);
});
Supplier<String> cleanedSupplier = atomicSupplier.get();
diff --git a/inject/hk2/src/test/java/org/glassfish/jersey/inject/hk2/DisposableSupplierTest.java b/inject/hk2/src/test/java/org/glassfish/jersey/inject/hk2/DisposableSupplierTest.java
index 89d2db3..bb290a2 100644
--- a/inject/hk2/src/test/java/org/glassfish/jersey/inject/hk2/DisposableSupplierTest.java
+++ b/inject/hk2/src/test/java/org/glassfish/jersey/inject/hk2/DisposableSupplierTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2024 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
@@ -17,6 +17,8 @@
package org.glassfish.jersey.inject.hk2;
import java.lang.reflect.Type;
+import java.util.HashSet;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
@@ -374,9 +376,17 @@
// All instances should be the same because they are request scoped.
ComposedObject instance = injectionManager.getInstance(ComposedObject.class);
- assertEquals("1", instance.first);
- assertEquals("2", instance.second);
- assertEquals("3", instance.third);
+ Set<String> set1 = new HashSet<String>() {{
+ add("1");
+ add("2");
+ add("3");
+ }};
+ Set<String> set2 = new HashSet<String>() {{
+ add(instance.first.toString());
+ add(instance.second.toString());
+ add(instance.third.toString());
+ }};
+ assertEquals(set1, set2);
});
Supplier<String> cleanedSupplier = atomicSupplier.get();
diff --git a/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForBothModulesTest.java b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForBothModulesTest.java
index 59d19c1..e9b621a 100644
--- a/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForBothModulesTest.java
+++ b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForBothModulesTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2024 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
@@ -23,6 +23,9 @@
import jakarta.ws.rs.core.Application;
+import java.util.List;
+import java.util.Arrays;
+import java.util.Collections;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class DefaultJsonJacksonProviderForBothModulesTest extends JerseyTest {
@@ -36,8 +39,12 @@
public final void testDisabledModule() {
final String response = target("entity/simple")
.request().get(String.class);
+ String expected = "{\"name\":\"Hello\",\"value\":\"World\"}";
+ List<String> response_list = Arrays.asList(response.replaceAll("[{}]", "").split(","));
+ List<String> expected_list = Arrays.asList(expected.replaceAll("[{}]", "").split(","));
+ Collections.sort(response_list);
- assertEquals("{\"name\":\"Hello\",\"value\":\"World\"}", response);
+ assertEquals(expected_list, response_list);
}
}
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/Issue5783Test.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/Issue5783Test.java
new file mode 100644
index 0000000..ab7b301
--- /dev/null
+++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/Issue5783Test.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2024 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
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.tests.e2e.server;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ContainerResponseContext;
+import jakarta.ws.rs.container.ContainerResponseFilter;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.ext.Provider;
+
+import org.glassfish.jersey.server.ContainerRequest;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.server.spi.ContainerResponseWriter;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.jupiter.api.Test;
+
+public class Issue5783Test extends JerseyTest {
+
+ private static final String ERROR = "Intentional issue5783 exception";
+ private static volatile String exceptionMessage;
+
+ @Override
+ protected Application configure() {
+ return new ResourceConfig(Resource.class, ResponseFilter.class);
+ }
+
+ @Test
+ public void closeException() throws InterruptedException {
+ target("/test").request().get();
+ assertEquals(ERROR, exceptionMessage);
+ }
+
+ @Path("/test")
+ public static class Resource {
+
+ @GET
+ public Response closeException(@Context ContainerRequest request) {
+ // Save the exception when response.getRequestContext().getResponseWriter().failure(e)
+ ContainerResponseWriter writer = request.getResponseWriter();
+ ContainerResponseWriter proxy = (ContainerResponseWriter) Proxy.newProxyInstance(
+ ContainerResponseWriter.class.getClassLoader(),
+ new Class<?>[]{ContainerResponseWriter.class}, new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if ("failure".equals(method.getName())) {
+ exceptionMessage = ((Throwable) args[0]).getCause().getMessage();
+ }
+ return method.invoke(writer, args);
+ }
+ });
+ request.setWriter(proxy);
+ return Response.ok().build();
+ }
+ }
+
+ @Provider
+ public static class ResponseFilter implements ContainerResponseFilter {
+ @Override
+ public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
+ throws IOException {
+ // Hack it to make ContainerResponse#close throws one exception
+ responseContext.setEntity("something");
+ responseContext.setEntityStream(new ByteArrayOutputStream() {
+ @Override
+ public void close() throws IOException {
+ throw new IOException(ERROR);
+ }
+ });
+ }
+ }
+}