Merge remote-tracking branch 'upstream/3.x' into 3.1

Signed-off-by: Maxim Nesen <maxim.nesen@oracle.com>
diff --git a/bom/pom.xml b/bom/pom.xml
index 8584f51..c5393d2 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -290,6 +290,11 @@
             </dependency>
             <dependency>
                 <groupId>org.glassfish.jersey.media</groupId>
+                <artifactId>jersey-media-json-gson</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.glassfish.jersey.media</groupId>
                 <artifactId>jersey-media-json-binding</artifactId>
                 <version>${project.version}</version>
             </dependency>
diff --git a/connectors/apache-connector/pom.xml b/connectors/apache-connector/pom.xml
index f366855..258ef18 100644
--- a/connectors/apache-connector/pom.xml
+++ b/connectors/apache-connector/pom.xml
@@ -40,6 +40,18 @@
         <dependency>
             <groupId>org.apache.httpcomponents</groupId>
             <artifactId>httpclient</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>commons-codec</groupId>
+                    <artifactId>commons-codec</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+            <version>${commons.codec.version}</version>
+            <scope>test</scope>
         </dependency>
 
         <dependency>
diff --git a/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java b/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java
index 0b08871..fdfbccf 100644
--- a/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java
+++ b/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java
@@ -29,6 +29,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Future;
 import java.util.concurrent.atomic.AtomicLong;
@@ -51,6 +52,7 @@
 import org.glassfish.jersey.client.ClientRequest;
 import org.glassfish.jersey.client.ClientResponse;
 import org.glassfish.jersey.client.RequestEntityProcessing;
+import org.glassfish.jersey.client.innate.ClientProxy;
 import org.glassfish.jersey.client.spi.AsyncConnectorCallback;
 import org.glassfish.jersey.client.spi.Connector;
 import org.glassfish.jersey.internal.util.PropertiesHelper;
@@ -279,28 +281,20 @@
             clientBuilder.setRetryHandler((HttpRequestRetryHandler) retryHandler);
         }
 
-        final Object proxyUri;
-        proxyUri = config.getProperty(ClientProperties.PROXY_URI);
-        if (proxyUri != null) {
-            final URI u = getProxyUri(proxyUri);
-            final HttpHost proxy = new HttpHost(u.getHost(), u.getPort(), u.getScheme());
-            final String userName;
-            userName = ClientProperties.getValue(config.getProperties(), ClientProperties.PROXY_USERNAME, String.class);
-            if (userName != null) {
-                final String password;
-                password = ClientProperties.getValue(config.getProperties(), ClientProperties.PROXY_PASSWORD, String.class);
-
-                if (password != null) {
-                    final CredentialsProvider credsProvider = new BasicCredentialsProvider();
-                    credsProvider.setCredentials(
-                            new AuthScope(u.getHost(), u.getPort()),
-                            new UsernamePasswordCredentials(userName, password)
-                    );
-                    clientBuilder.setDefaultCredentialsProvider(credsProvider);
-                }
+        final Optional<ClientProxy> proxy = ClientProxy.proxyFromConfiguration(config);
+        proxy.ifPresent(clientProxy -> {
+            final URI u = clientProxy.uri();
+            final HttpHost proxyHost = new HttpHost(u.getHost(), u.getPort(), u.getScheme());
+            if (clientProxy.userName() != null && clientProxy.password() != null) {
+                final CredentialsProvider credsProvider = new BasicCredentialsProvider();
+                credsProvider.setCredentials(
+                        new AuthScope(u.getHost(), u.getPort()),
+                        new UsernamePasswordCredentials(clientProxy.userName(), clientProxy.password())
+                );
+                clientBuilder.setDefaultCredentialsProvider(credsProvider);
             }
-            clientBuilder.setProxy(proxy);
-        }
+            clientBuilder.setProxy(proxyHost);
+        });
 
         final Boolean preemptiveBasicAuthProperty = (Boolean) config.getProperties()
                 .get(ApacheClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION);
@@ -452,16 +446,6 @@
         return cookieStore;
     }
 
-    private static URI getProxyUri(final Object proxy) {
-        if (proxy instanceof URI) {
-            return (URI) proxy;
-        } else if (proxy instanceof String) {
-            return URI.create((String) proxy);
-        } else {
-            throw new ProcessingException(LocalizationMessages.WRONG_PROXY_URI_TYPE(ClientProperties.PROXY_URI));
-        }
-    }
-
     @Override
     public ClientResponse apply(final ClientRequest clientRequest) throws ProcessingException {
         final HttpUriRequest request = getUriHttpRequest(clientRequest);
diff --git a/connectors/apache-connector/src/main/resources/org/glassfish/jersey/apache/connector/localization.properties b/connectors/apache-connector/src/main/resources/org/glassfish/jersey/apache/connector/localization.properties
index f0cc55b..3b06461 100644
--- a/connectors/apache-connector/src/main/resources/org/glassfish/jersey/apache/connector/localization.properties
+++ b/connectors/apache-connector/src/main/resources/org/glassfish/jersey/apache/connector/localization.properties
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 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
@@ -19,7 +19,5 @@
 failed.to.stop.client=Failed to stop the client.
 # {0} - property name, e.g. jersey.config.client.httpclient.connectionManager; {1}, {2} - full class name
 ignoring.value.of.property=Ignoring value of property "{0}" ("{1}") - not instance of "{2}".
-# {0} - property name - jersey.config.client.httpclient.proxyUri
-wrong.proxy.uri.type=The proxy URI ("{0}") property MUST be an instance of String or URI.
 invalid.configurable.component.type=The supplied component "{0}" is not assignable from JerseyClient or JerseyWebTarget.
 expected.connector.provider.not.used=The supplied component is not configured to use a ApacheConnectorProvider.
diff --git a/connectors/apache5-connector/pom.xml b/connectors/apache5-connector/pom.xml
index 6e24418..9d08082 100644
--- a/connectors/apache5-connector/pom.xml
+++ b/connectors/apache5-connector/pom.xml
@@ -40,9 +40,21 @@
         <dependency>
             <groupId>org.apache.httpcomponents.client5</groupId>
             <artifactId>httpclient5</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-api</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
 
         <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>${slf4j.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.glassfish.jersey.containers</groupId>
             <artifactId>jersey-container-grizzly2-http</artifactId>
             <version>${project.version}</version>
diff --git a/connectors/apache5-connector/src/main/java/org/glassfish/jersey/apache5/connector/Apache5Connector.java b/connectors/apache5-connector/src/main/java/org/glassfish/jersey/apache5/connector/Apache5Connector.java
index 5cc2e63..9e4e9ac 100644
--- a/connectors/apache5-connector/src/main/java/org/glassfish/jersey/apache5/connector/Apache5Connector.java
+++ b/connectors/apache5-connector/src/main/java/org/glassfish/jersey/apache5/connector/Apache5Connector.java
@@ -30,6 +30,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Future;
 import java.util.logging.Level;
@@ -93,6 +94,7 @@
 import org.glassfish.jersey.client.ClientRequest;
 import org.glassfish.jersey.client.ClientResponse;
 import org.glassfish.jersey.client.RequestEntityProcessing;
+import org.glassfish.jersey.client.innate.ClientProxy;
 import org.glassfish.jersey.client.spi.AsyncConnectorCallback;
 import org.glassfish.jersey.client.spi.Connector;
 import org.glassfish.jersey.internal.util.PropertiesHelper;
@@ -280,28 +282,20 @@
             clientBuilder.setRetryStrategy((HttpRequestRetryStrategy) retryHandler);
         }
 
-        final Object proxyUri;
-        proxyUri = config.getProperty(ClientProperties.PROXY_URI);
-        if (proxyUri != null) {
-            final URI u = getProxyUri(proxyUri);
-            final HttpHost proxy = new HttpHost(u.getScheme(), u.getHost(), u.getPort());
-            final String userName;
-            userName = ClientProperties.getValue(config.getProperties(), ClientProperties.PROXY_USERNAME, String.class);
-            if (userName != null) {
-                final String password;
-                password = ClientProperties.getValue(config.getProperties(), ClientProperties.PROXY_PASSWORD, String.class);
-
-                if (password != null) {
-                    final CredentialsStore credsProvider = new BasicCredentialsProvider();
-                    credsProvider.setCredentials(
-                            new AuthScope(u.getHost(), u.getPort()),
-                            new UsernamePasswordCredentials(userName, password.toCharArray())
-                    );
-                    clientBuilder.setDefaultCredentialsProvider(credsProvider);
-                }
+        final Optional<ClientProxy> proxy = ClientProxy.proxyFromConfiguration(config);
+        proxy.ifPresent(clientProxy -> {
+            final URI u = clientProxy.uri();
+            final HttpHost proxyHost = new HttpHost(u.getScheme(), u.getHost(), u.getPort());
+            if (clientProxy.userName() != null && clientProxy.password() != null) {
+                final CredentialsStore credsProvider = new BasicCredentialsProvider();
+                credsProvider.setCredentials(
+                        new AuthScope(u.getHost(), u.getPort()),
+                        new UsernamePasswordCredentials(clientProxy.userName(), clientProxy.password().toCharArray())
+                );
+                clientBuilder.setDefaultCredentialsProvider(credsProvider);
             }
-            clientBuilder.setProxy(proxy);
-        }
+            clientBuilder.setProxy(proxyHost);
+        });
 
         final Boolean preemptiveBasicAuthProperty = (Boolean) config.getProperties()
                 .get(Apache5ClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION);
@@ -456,16 +450,6 @@
         return cookieStore;
     }
 
-    private static URI getProxyUri(final Object proxy) {
-        if (proxy instanceof URI) {
-            return (URI) proxy;
-        } else if (proxy instanceof String) {
-            return URI.create((String) proxy);
-        } else {
-            throw new ProcessingException(LocalizationMessages.WRONG_PROXY_URI_TYPE(ClientProperties.PROXY_URI));
-        }
-    }
-
     @Override
     public ClientResponse apply(final ClientRequest clientRequest) throws ProcessingException {
         final HttpUriRequest request = getUriHttpRequest(clientRequest);
diff --git a/connectors/apache5-connector/src/main/resources/org/glassfish/jersey/apache5/connector/localization.properties b/connectors/apache5-connector/src/main/resources/org/glassfish/jersey/apache5/connector/localization.properties
index 16dbc30..1f6e4a6 100644
--- a/connectors/apache5-connector/src/main/resources/org/glassfish/jersey/apache5/connector/localization.properties
+++ b/connectors/apache5-connector/src/main/resources/org/glassfish/jersey/apache5/connector/localization.properties
@@ -19,7 +19,5 @@
 failed.to.stop.client=Failed to stop the client.
 # {0} - property name, e.g. jersey.config.client.httpclient.connectionManager; {1}, {2} - full class name
 ignoring.value.of.property=Ignoring value of property "{0}" ("{1}") - not instance of "{2}".
-# {0} - property name - jersey.config.client.httpclient.proxyUri
-wrong.proxy.uri.type=The proxy URI ("{0}") property MUST be an instance of String or URI.
 invalid.configurable.component.type=The supplied component "{0}" is not assignable from JerseyClient or JerseyWebTarget.
 expected.connector.provider.not.used=The supplied component is not configured to use a ApacheConnectorProvider.
diff --git a/connectors/grizzly-connector/pom.xml b/connectors/grizzly-connector/pom.xml
index a9327a5..ba96bfd 100644
--- a/connectors/grizzly-connector/pom.xml
+++ b/connectors/grizzly-connector/pom.xml
@@ -49,9 +49,18 @@
                     <groupId>org.glassfish.grizzly</groupId>
                     <artifactId>connection-pool</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-api</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
         <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>${slf4j.version}</version>
+        </dependency>
+        <dependency>
             <groupId>org.glassfish.grizzly</groupId>
             <artifactId>grizzly-websockets</artifactId>
         </dependency>
diff --git a/connectors/grizzly-connector/src/main/java/org/glassfish/jersey/grizzly/connector/GrizzlyConnector.java b/connectors/grizzly-connector/src/main/java/org/glassfish/jersey/grizzly/connector/GrizzlyConnector.java
index c1ff43d..f39e216 100644
--- a/connectors/grizzly-connector/src/main/java/org/glassfish/jersey/grizzly/connector/GrizzlyConnector.java
+++ b/connectors/grizzly-connector/src/main/java/org/glassfish/jersey/grizzly/connector/GrizzlyConnector.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -22,6 +22,7 @@
 import java.net.URI;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Properties;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
@@ -39,6 +40,7 @@
 import org.glassfish.jersey.client.ClientRequest;
 import org.glassfish.jersey.client.ClientResponse;
 import org.glassfish.jersey.client.RequestEntityProcessing;
+import org.glassfish.jersey.client.innate.ClientProxy;
 import org.glassfish.jersey.client.spi.AsyncConnectorCallback;
 import org.glassfish.jersey.client.spi.Connector;
 import org.glassfish.jersey.internal.Version;
@@ -83,7 +85,7 @@
     GrizzlyConnector(final Client client,
                      final Configuration config,
                      final GrizzlyConnectorProvider.AsyncClientCustomizer asyncClientCustomizer) {
-        AsyncHttpClientConfig.Builder builder = new AsyncHttpClientConfig.Builder();
+        final AsyncHttpClientConfig.Builder builder = new AsyncHttpClientConfig.Builder();
 
         ExecutorService executorService;
         if (config != null) {
@@ -95,7 +97,7 @@
                 executorService = Executors.newCachedThreadPool();
             }
 
-            builder = builder.setExecutorService(executorService);
+            builder.setExecutorService(executorService);
 
             builder.setConnectTimeout(ClientProperties.getValue(config.getProperties(),
                                                                 ClientProperties.CONNECT_TIMEOUT, 10000));
@@ -103,29 +105,23 @@
             builder.setRequestTimeout(ClientProperties.getValue(config.getProperties(),
                                                                 ClientProperties.READ_TIMEOUT, 10000));
 
-            Object proxyUri;
-            proxyUri = config.getProperty(ClientProperties.PROXY_URI);
-            if (proxyUri != null) {
-                final URI u = getProxyUri(proxyUri);
+            final Optional<ClientProxy> proxy = ClientProxy.proxyFromConfiguration(config);
+            proxy.ifPresent(clientProxy -> {
+                final URI u = clientProxy.uri();
                 final Properties proxyProperties = new Properties();
                 proxyProperties.setProperty(ProxyUtils.PROXY_PROTOCOL, u.getScheme());
                 proxyProperties.setProperty(ProxyUtils.PROXY_HOST, u.getHost());
                 proxyProperties.setProperty(ProxyUtils.PROXY_PORT, String.valueOf(u.getPort()));
 
-                final String userName = ClientProperties.getValue(
-                        config.getProperties(), ClientProperties.PROXY_USERNAME, String.class);
-                if (userName != null) {
-                    proxyProperties.setProperty(ProxyUtils.PROXY_USER, userName);
-
-                    final String password = ClientProperties.getValue(
-                            config.getProperties(), ClientProperties.PROXY_PASSWORD, String.class);
-                    if (password != null) {
-                        proxyProperties.setProperty(ProxyUtils.PROXY_PASSWORD, password);
+                if (clientProxy.userName() != null) {
+                    proxyProperties.setProperty(ProxyUtils.PROXY_USER, clientProxy.userName());
+                    if (clientProxy.password() != null) {
+                        proxyProperties.setProperty(ProxyUtils.PROXY_PASSWORD, clientProxy.password());
                     }
                 }
                 ProxyServerSelector proxyServerSelector = ProxyUtils.createProxyServerSelector(proxyProperties);
                 builder.setProxyServerSelector(proxyServerSelector);
-            }
+            });
         } else {
             executorService = Executors.newCachedThreadPool();
             builder.setExecutorService(executorService);
@@ -140,7 +136,7 @@
         }
 
         if (asyncClientCustomizer != null) {
-            builder = asyncClientCustomizer.customize(client, config, builder);
+            asyncClientCustomizer.customize(client, config, builder);
         }
 
         AsyncHttpClientConfig asyncClientConfig = builder.build();
@@ -148,17 +144,6 @@
         this.grizzlyClient = new AsyncHttpClient(new GrizzlyAsyncHttpProvider(asyncClientConfig), asyncClientConfig);
     }
 
-    @SuppressWarnings("ChainOfInstanceofChecks")
-    private static URI getProxyUri(final Object proxy) {
-        if (proxy instanceof URI) {
-            return (URI) proxy;
-        } else if (proxy instanceof String) {
-            return URI.create((String) proxy);
-        } else {
-            throw new ProcessingException(LocalizationMessages.WRONG_PROXY_URI_TYPE(ClientProperties.PROXY_URI));
-        }
-    }
-
     /**
      * Get the underlying Grizzly {@link com.ning.http.client.AsyncHttpClient} instance.
      *
diff --git a/connectors/grizzly-connector/src/main/resources/org/glassfish/jersey/grizzly/connector/localization.properties b/connectors/grizzly-connector/src/main/resources/org/glassfish/jersey/grizzly/connector/localization.properties
index 7fb050e..2d577c6 100644
--- a/connectors/grizzly-connector/src/main/resources/org/glassfish/jersey/grizzly/connector/localization.properties
+++ b/connectors/grizzly-connector/src/main/resources/org/glassfish/jersey/grizzly/connector/localization.properties
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 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
@@ -16,5 +16,4 @@
 
 error.buffering.entity=Error buffering the entity.
 expected.connector.provider.not.used=The supplied component is not configured to use a GrizzlyConnectorProvider.
-invalid.configurable.component.type=The supplied component "{0}" is not assignable from JerseyClient or JerseyWebTarget.
-wrong.proxy.uri.type=The proxy URI ("{0}") property MUST be an instance of String or URI.
+invalid.configurable.component.type=The supplied component "{0}" is not assignable from JerseyClient or JerseyWebTarget.
\ No newline at end of file
diff --git a/connectors/jetty-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnector.java b/connectors/jetty-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnector.java
index 655a203..504fb0e 100644
--- a/connectors/jetty-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnector.java
+++ b/connectors/jetty-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnector.java
@@ -57,6 +57,7 @@
 import org.glassfish.jersey.client.ClientProperties;
 import org.glassfish.jersey.client.ClientRequest;
 import org.glassfish.jersey.client.ClientResponse;
+import org.glassfish.jersey.client.innate.ClientProxy;
 import org.glassfish.jersey.client.spi.AsyncConnectorCallback;
 import org.glassfish.jersey.client.spi.Connector;
 import org.glassfish.jersey.internal.util.collection.ByteBufferInputStream;
@@ -193,19 +194,17 @@
             auth.addAuthentication((BasicAuthentication) basicAuthProvider);
         }
 
-        final Object proxyUri = config.getProperties().get(ClientProperties.PROXY_URI);
-        if (proxyUri != null) {
-            final URI u = getProxyUri(proxyUri);
+        final Optional<ClientProxy> proxy = ClientProxy.proxyFromConfiguration(config);
+        proxy.ifPresent(clientProxy -> {
             final ProxyConfiguration proxyConfig = client.getProxyConfiguration();
+            final URI u = clientProxy.uri();
             proxyConfig.getProxies().add(new HttpProxy(u.getHost(), u.getPort()));
 
-            final Object proxyUsername = config.getProperties().get(ClientProperties.PROXY_USERNAME);
-            if (proxyUsername != null) {
-                final Object proxyPassword = config.getProperties().get(ClientProperties.PROXY_PASSWORD);
+            if (clientProxy.userName() != null) {
                 auth.addAuthentication(new BasicAuthentication(u, "<<ANY_REALM>>",
-                        String.valueOf(proxyUsername), String.valueOf(proxyPassword)));
+                        clientProxy.userName(), clientProxy.password()));
             }
-        }
+        });
 
         if (disableCookies) {
             client.setCookieStore(new HttpCookieStore.Empty());
@@ -229,17 +228,6 @@
         this.cookieStore = client.getCookieStore();
     }
 
-    @SuppressWarnings("ChainOfInstanceofChecks")
-    private static URI getProxyUri(final Object proxy) {
-        if (proxy instanceof URI) {
-            return (URI) proxy;
-        } else if (proxy instanceof String) {
-            return URI.create((String) proxy);
-        } else {
-            throw new ProcessingException(LocalizationMessages.WRONG_PROXY_URI_TYPE(ClientProperties.PROXY_URI));
-        }
-    }
-
     /**
      * Get the {@link HttpClient}.
      *
diff --git a/connectors/jetty-connector/src/main/resources/org/glassfish/jersey/jetty/connector/localization.properties b/connectors/jetty-connector/src/main/resources/org/glassfish/jersey/jetty/connector/localization.properties
index af11518..128d40b 100644
--- a/connectors/jetty-connector/src/main/resources/org/glassfish/jersey/jetty/connector/localization.properties
+++ b/connectors/jetty-connector/src/main/resources/org/glassfish/jersey/jetty/connector/localization.properties
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 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
@@ -16,8 +16,6 @@
 
 # {0} - HTTP method, e.g. GET, DELETE
 method.not.supported=Method {0} not supported.
-# {0} - property name - jersey.config.client.proxyUri
-wrong.proxy.uri.type=The proxy URI ("{0}") property MUST be an instance of String or URI.
 invalid.configurable.component.type=The supplied component "{0}" is not assignable from JerseyClient or JerseyWebTarget.
 expected.connector.provider.not.used=The supplied component is not configured to use a JettyConnectorProvider.
 not.supported=Jetty connector is not supported on JDK version less than 11.
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 77d0d27..5d52e76 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
@@ -19,8 +19,6 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.net.InetSocketAddress;
-import java.net.Proxy;
-import java.net.ProxySelector;
 import java.net.SocketAddress;
 import java.net.URI;
 import java.util.ArrayList;
@@ -29,6 +27,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionException;
@@ -48,7 +47,6 @@
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelDuplexHandler;
 import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelInboundHandlerAdapter;
 import io.netty.channel.ChannelInitializer;
 import io.netty.channel.ChannelOption;
 import io.netty.channel.ChannelPipeline;
@@ -69,7 +67,6 @@
 import io.netty.handler.codec.http.HttpUtil;
 import io.netty.handler.codec.http.HttpVersion;
 import io.netty.handler.proxy.HttpProxyHandler;
-import io.netty.handler.proxy.ProxyConnectionEvent;
 import io.netty.handler.proxy.ProxyHandler;
 import io.netty.handler.ssl.ApplicationProtocolConfig;
 import io.netty.handler.ssl.ClientAuth;
@@ -80,10 +77,12 @@
 import io.netty.handler.timeout.IdleState;
 import io.netty.handler.timeout.IdleStateEvent;
 import io.netty.handler.timeout.IdleStateHandler;
+import io.netty.resolver.NoopAddressResolverGroup;
 import io.netty.util.concurrent.GenericFutureListener;
 import org.glassfish.jersey.client.ClientProperties;
 import org.glassfish.jersey.client.ClientRequest;
 import org.glassfish.jersey.client.ClientResponse;
+import org.glassfish.jersey.client.innate.ClientProxy;
 import org.glassfish.jersey.client.spi.AsyncConnectorCallback;
 import org.glassfish.jersey.client.spi.Connector;
 import org.glassfish.jersey.message.internal.OutboundMessageContext;
@@ -235,6 +234,18 @@
 
             if (chan == null) {
                Bootstrap b = new Bootstrap();
+
+               // http proxy
+               Optional<ClientProxy> proxy = ClientProxy.proxyFromRequest(jerseyRequest);
+               if (!proxy.isPresent()) {
+                   proxy = ClientProxy.proxyFromProperties(requestUri);
+               }
+               proxy.ifPresent(clientProxy -> {
+                   b.resolver(NoopAddressResolverGroup.INSTANCE); // request hostname resolved by the HTTP proxy
+               });
+
+               final Optional<ClientProxy> handlerProxy = proxy;
+
                b.group(group)
                 .channel(NioSocketChannel.class)
                 .handler(new ChannelInitializer<SocketChannel>() {
@@ -245,41 +256,14 @@
                      Configuration config = jerseyRequest.getConfiguration();
 
                      // http proxy
-                     final Object proxyUri = config.getProperties().get(ClientProperties.PROXY_URI);
-                     if (proxyUri != null) {
-                         final URI u = getProxyUri(proxyUri);
-
-                         final String userName = ClientProperties.getValue(
-                                 config.getProperties(), ClientProperties.PROXY_USERNAME, String.class);
-                         final String password = ClientProperties.getValue(
-                                 config.getProperties(), ClientProperties.PROXY_PASSWORD, String.class);
-
+                     handlerProxy.ifPresent(clientProxy -> {
+                         final URI u = clientProxy.uri();
                          InetSocketAddress proxyAddr = new InetSocketAddress(u.getHost(),
-                                                                             u.getPort() == -1 ? 8080 : u.getPort());
-                         ProxyHandler proxy = createProxyHandler(jerseyRequest, proxyAddr, userName, password, connectTimeout);
-                         p.addLast(proxy);
-                     } else {
-                         ProxySelector sel = ProxySelector.getDefault();
-                         for (Proxy proxy: sel.select(requestUri)) {
-                             if (Proxy.Type.HTTP.equals(proxy.type())) {
-                                 SocketAddress proxyAddress = proxy.address();
-                                 if (InetSocketAddress.class.isInstance(proxy.address())) {
-                                     InetSocketAddress proxyAddr = (InetSocketAddress) proxyAddress;
-                                     if (proxyAddr.isUnresolved()
-                                             && proxyAddr.getHostName() != null
-                                             && proxyAddr.getHostName().startsWith("http://")) {
-                                         proxyAddress = new InetSocketAddress(
-                                                 proxyAddr.getHostString().substring(7), proxyAddr.getPort()
-                                         );
-                                     }
-                                 }
-                                 ProxyHandler proxyHandler
-                                         = createProxyHandler(jerseyRequest, proxyAddress, null, null, connectTimeout);
-                                 p.addLast(proxyHandler);
-                                 break;
-                             }
-                         }
-                     }
+                                 u.getPort() == -1 ? 8080 : u.getPort());
+                         ProxyHandler proxy1 = createProxyHandler(jerseyRequest, proxyAddr,
+                                 clientProxy.userName(), clientProxy.password(), connectTimeout);
+                         p.addLast(proxy1);
+                     });
 
                      // Enable HTTPS if necessary.
                      if ("https".equals(requestUri.getScheme())) {
@@ -471,17 +455,6 @@
         executorService.shutdown();
     }
 
-    @SuppressWarnings("ChainOfInstanceofChecks")
-    private static URI getProxyUri(final Object proxy) {
-        if (proxy instanceof URI) {
-            return (URI) proxy;
-        } else if (proxy instanceof String) {
-            return URI.create((String) proxy);
-        } else {
-            throw new ProcessingException(LocalizationMessages.WRONG_PROXY_URI_TYPE(ClientProperties.PROXY_URI));
-        }
-    }
-
     protected static class PruneIdlePool extends ChannelDuplexHandler {
        HashMap<String, ArrayList<Channel>> connections;
        String key;
diff --git a/connectors/netty-connector/src/main/resources/org/glassfish/jersey/netty/connector/localization.properties b/connectors/netty-connector/src/main/resources/org/glassfish/jersey/netty/connector/localization.properties
index 9055d62..ba91c4f 100644
--- a/connectors/netty-connector/src/main/resources/org/glassfish/jersey/netty/connector/localization.properties
+++ b/connectors/netty-connector/src/main/resources/org/glassfish/jersey/netty/connector/localization.properties
@@ -14,7 +14,6 @@
 # SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 #
 
-wrong.proxy.uri.type=The proxy URI ("{0}") property MUST be an instance of String or URI.
 wrong.read.timeout=Unexpected ("{0}") READ_TIMEOUT.
 wrong.max.pool.size=Unexpected ("{0}") maximum number of connections per destination.
 wrong.max.pool.total=Unexpected ("{0}") maximum number of connections total.
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/ClientProperties.java b/core-client/src/main/java/org/glassfish/jersey/client/ClientProperties.java
index 411100b..909af8d 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/ClientProperties.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/ClientProperties.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/HttpUrlConnectorProvider.java b/core-client/src/main/java/org/glassfish/jersey/client/HttpUrlConnectorProvider.java
index 5a07bc1..056f474 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/HttpUrlConnectorProvider.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/HttpUrlConnectorProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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 java.io.IOException;
 import java.net.HttpURLConnection;
+import java.net.Proxy;
 import java.net.URL;
 import java.util.Map;
 import java.util.logging.Logger;
@@ -267,6 +268,23 @@
          * @throws java.io.IOException in case the connection cannot be provided.
          */
         public HttpURLConnection getConnection(URL url) throws IOException;
+
+        /**
+         * Get a {@link java.net.HttpURLConnection} for a given URL.
+         * <p>
+         * Implementation of the method MUST be thread-safe and MUST ensure that
+         * a dedicated {@link java.net.HttpURLConnection} instance is returned for concurrent
+         * requests.
+         * </p>
+         *
+         * @param url the endpoint URL.
+         * @param proxy the configured proxy or null.
+         * @return the {@link java.net.HttpURLConnection}.
+         * @throws java.io.IOException in case the connection cannot be provided.
+         */
+        default HttpURLConnection getConnection(URL url, Proxy proxy) throws IOException {
+            return (proxy == null) ? getConnection(url) : (HttpURLConnection) url.openConnection(proxy);
+        }
     }
 
     private static class DefaultConnectionFactory implements ConnectionFactory {
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/innate/ClientProxy.java b/core-client/src/main/java/org/glassfish/jersey/client/innate/ClientProxy.java
new file mode 100644
index 0000000..68ab324
--- /dev/null
+++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/ClientProxy.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 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
+ * 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.client.innate;
+
+import org.glassfish.jersey.client.ClientProperties;
+import org.glassfish.jersey.client.ClientRequest;
+import org.glassfish.jersey.client.internal.LocalizationMessages;
+
+import jakarta.ws.rs.ProcessingException;
+import jakarta.ws.rs.core.Configuration;
+import jakarta.ws.rs.core.MultivaluedMap;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.ProxySelector;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.Locale;
+import java.util.Optional;
+
+/**
+ * Default client Proxy information internal object. It is used for parsing the proxy information in all connectors.
+ */
+public abstract class ClientProxy {
+
+    private ClientProxy() {
+      // do not instantiate
+    };
+
+    public static Optional<ClientProxy> proxyFromRequest(ClientRequest request) {
+        return getProxy(request);
+    }
+
+    public static Optional<ClientProxy> proxyFromProperties(URI requestUri) {
+        return getSystemPropertiesProxy(requestUri);
+    }
+
+    public static Optional<ClientProxy> proxyFromConfiguration(Configuration configuration) {
+        return getProxy(configuration);
+    }
+
+    public static ClientProxy proxy(Proxy proxy) {
+        return new ProxyClientProxy(proxy);
+    }
+
+    public static void setBasicAuthorizationHeader(MultivaluedMap<String, Object> headers, ClientProxy proxy) {
+        if (proxy.userName() != null) {
+            StringBuilder auth = new StringBuilder().append(proxy.userName()).append(":");
+            if (proxy.password() != null) {
+                auth.append(proxy.password());
+            }
+            String encoded = "Basic " + Base64.getEncoder().encodeToString(auth.toString().getBytes());
+            headers.put("Proxy-Authorization", Arrays.asList(encoded));
+        }
+    }
+
+    protected String userName;
+    protected String password;
+
+    private static ClientProxy toProxy(Object proxy) {
+        if (proxy instanceof String) {
+            return new UriClientProxy(URI.create((String) proxy));
+        } else if (proxy instanceof URI) {
+            return new UriClientProxy((URI) proxy);
+        } else if (Proxy.class.isInstance(proxy)) {
+            Proxy netProxy = Proxy.class.cast(proxy);
+            if (Proxy.Type.HTTP.equals(netProxy.type())) {
+                return new ProxyClientProxy(Proxy.class.cast(proxy));
+            } else {
+                return null;
+            }
+        } else {
+            throw new ProcessingException(LocalizationMessages.WRONG_PROXY_URI_TYPE(ClientProperties.PROXY_URI));
+        }
+    }
+
+    public abstract Proxy proxy();
+
+    public abstract URI uri();
+
+    public abstract Proxy.Type type();
+
+    public String password() {
+        return password;
+    }
+
+    public String userName() {
+        return userName;
+    };
+
+    private static Optional<ClientProxy> getProxy(ClientRequest request) {
+        Object proxyUri = request.resolveProperty(ClientProperties.PROXY_URI, Object.class);
+        if (proxyUri != null) {
+            ClientProxy proxy = toProxy(proxyUri);
+            if (proxy != null) {
+                proxy.userName = request.resolveProperty(ClientProperties.PROXY_USERNAME, String.class);
+                proxy.password = request.resolveProperty(ClientProperties.PROXY_PASSWORD, String.class);
+                return Optional.of(proxy);
+            } else {
+                return Optional.empty();
+            }
+        }
+        return Optional.empty();
+    }
+
+    private static Optional<ClientProxy> getProxy(Configuration config) {
+        Object proxyUri = config.getProperties().get(ClientProperties.PROXY_URI);
+        if (proxyUri != null) {
+            ClientProxy proxy = toProxy(proxyUri);
+            if (proxy != null) {
+                proxy.userName = ClientProperties.getValue(config.getProperties(), ClientProperties.PROXY_USERNAME, String.class);
+                proxy.password = ClientProperties.getValue(config.getProperties(), ClientProperties.PROXY_PASSWORD, String.class);
+                return Optional.of(proxy);
+            } else {
+                return Optional.empty();
+            }
+        }
+        return Optional.empty();
+    }
+
+    private static Optional<ClientProxy> getSystemPropertiesProxy(URI requestUri) {
+        ProxySelector sel = ProxySelector.getDefault();
+        for (Proxy proxy: sel.select(requestUri)) {
+            if (Proxy.Type.HTTP.equals(proxy.type())) {
+                return Optional.of(new ProxyClientProxy(proxy));
+            }
+        }
+        return Optional.empty();
+    }
+
+    private static final class ProxyClientProxy extends ClientProxy {
+
+        private final Proxy proxy;
+
+        private ProxyClientProxy(Proxy proxy) {
+            this.proxy = proxy;
+        }
+
+        @Override
+        public Proxy proxy() {
+            return proxy;
+        }
+
+        @Override
+        public Proxy.Type type() {
+            return proxy.type();
+        }
+
+        @Override
+        public URI uri() {
+            URI uri = null;
+            if (Proxy.Type.HTTP.equals(proxy.type())) {
+                SocketAddress proxyAddress = proxy.address();
+                if (InetSocketAddress.class.isInstance(proxy.address())) {
+                    InetSocketAddress proxyAddr = (InetSocketAddress) proxyAddress;
+                    try {
+                        if (proxyAddr.isUnresolved()
+                                && proxyAddr.getHostName() != null
+                                && proxyAddr.getHostName().toLowerCase(Locale.ROOT).startsWith("http://")) {
+                            String hostString = proxyAddr.getHostString().substring(7);
+                            uri = new URI("http", null, hostString, proxyAddr.getPort(), null, null, null);
+                        } else {
+                            uri = new URI("http", null, proxyAddr.getHostString(), proxyAddr.getPort(), null, null, null);
+                        }
+                    } catch (URISyntaxException e) {
+                        throw new ProcessingException(e);
+                    }
+                }
+            }
+            return uri;
+        }
+    }
+
+    private static final class UriClientProxy extends ClientProxy {
+        private final URI uri;
+
+        private UriClientProxy(URI uri) {
+            this.uri = uri;
+        }
+
+        @Override
+        public Proxy proxy() {
+            return new Proxy(type(), new InetSocketAddress(uri.getHost(), uri.getPort()));
+        }
+
+        @Override
+        public Proxy.Type type() {
+            return Proxy.Type.HTTP;
+        }
+
+        @Override
+        public URI uri() {
+            return uri;
+        }
+    }
+}
+
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/innate/package-info.java b/core-client/src/main/java/org/glassfish/jersey/client/innate/package-info.java
new file mode 100644
index 0000000..016eea7
--- /dev/null
+++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 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
+ * 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
+ */
+
+/**
+ * Jersey client MOST INTERNAL classes/interfaces.
+ * Shall not be used outside of Jersey.
+ */
+package org.glassfish.jersey.client.innate;
\ No newline at end of file
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java b/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java
index 10f2387..31a3583 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/internal/HttpUrlConnector.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
@@ -32,6 +32,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Future;
@@ -39,21 +40,21 @@
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
 
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSocketFactory;
 import jakarta.ws.rs.ProcessingException;
 import jakarta.ws.rs.client.Client;
 import jakarta.ws.rs.core.MultivaluedMap;
 import jakarta.ws.rs.core.Response;
 
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLSocketFactory;
-
 import org.glassfish.jersey.client.ClientProperties;
 import org.glassfish.jersey.client.ClientRequest;
 import org.glassfish.jersey.client.ClientResponse;
 import org.glassfish.jersey.client.HttpUrlConnectorProvider;
 import org.glassfish.jersey.client.JerseyClient;
 import org.glassfish.jersey.client.RequestEntityProcessing;
+import org.glassfish.jersey.client.innate.ClientProxy;
 import org.glassfish.jersey.client.spi.AsyncConnectorCallback;
 import org.glassfish.jersey.client.spi.Connector;
 import org.glassfish.jersey.internal.util.PropertiesHelper;
@@ -316,8 +317,9 @@
 
     private ClientResponse _apply(final ClientRequest request) throws IOException {
         final HttpURLConnection uc;
-
-        uc = this.connectionFactory.getConnection(request.getUri().toURL());
+        Optional<ClientProxy> proxy = ClientProxy.proxyFromRequest(request);
+        proxy.ifPresent(clientProxy -> ClientProxy.setBasicAuthorizationHeader(request.getHeaders(), proxy.get()));
+        uc = this.connectionFactory.getConnection(request.getUri().toURL(), proxy.isPresent() ? proxy.get().proxy() : null);
         uc.setDoInput(true);
 
         final String httpMethod = request.getMethod();
diff --git a/core-client/src/main/resources/org/glassfish/jersey/client/internal/localization.properties b/core-client/src/main/resources/org/glassfish/jersey/client/internal/localization.properties
index 4bc0ae8..e66ceab 100644
--- a/core-client/src/main/resources/org/glassfish/jersey/client/internal/localization.properties
+++ b/core-client/src/main/resources/org/glassfish/jersey/client/internal/localization.properties
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 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
@@ -84,3 +84,5 @@
 error.listener.init=ClientLifecycleListener {0} failed to initialize properly.
 error.listener.close=ClientLifecycleListener {0} failed to close properly.
 error.shutdownhook.close=Client shutdown hook {0} failed.
+# {0} - property name - jersey.config.client.httpclient.proxyUri
+wrong.proxy.uri.type=The proxy URI ("{0}") property MUST be an instance of String or URI.
diff --git a/core-client/src/test/java/org/glassfish/jersey/client/HttpUrlConnectorTest.java b/core-client/src/test/java/org/glassfish/jersey/client/HttpUrlConnectorTest.java
index 5204144..7a00f1f 100644
--- a/core-client/src/test/java/org/glassfish/jersey/client/HttpUrlConnectorTest.java
+++ b/core-client/src/test/java/org/glassfish/jersey/client/HttpUrlConnectorTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
diff --git a/core-common/src/main/java/org/glassfish/jersey/ExternalProperties.java b/core-common/src/main/java/org/glassfish/jersey/ExternalProperties.java
index 04ef1bd..a8f6ec6 100644
--- a/core-common/src/main/java/org/glassfish/jersey/ExternalProperties.java
+++ b/core-common/src/main/java/org/glassfish/jersey/ExternalProperties.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 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
@@ -32,12 +32,22 @@
     public static final String HTTP_PROXY_PORT = "http.proxyPort";
 
     /**
-     * Property used to indicates the hosts that should be accessed
+     * Property used to indicate the hosts that should be accessed
      * without going through the proxy.
      */
     public static final String HTTP_NON_PROXY_HOSTS = "http.nonProxyHosts";
 
     /**
+     * Property used to specify the user name to authenticate with the proxy.
+     */
+    public static final String HTTP_PROXY_USER = "http.proxyUser";
+
+    /**
+     * Property used to specify the password to authenticate with the proxy.
+     */
+    public static final String HTTP_PROXY_PASSWORD = "http.proxyPassword";
+
+    /**
      * Prevent instantiation.
      */
     private ExternalProperties() {
diff --git a/examples/groovy/pom.xml b/examples/groovy/pom.xml
index c3cb714..49a7051 100644
--- a/examples/groovy/pom.xml
+++ b/examples/groovy/pom.xml
@@ -77,7 +77,7 @@
             <plugin>
                 <groupId>org.codehaus.gmavenplus</groupId>
                 <artifactId>gmavenplus-plugin</artifactId>
-                <version>1.12.1</version>
+                <version>${org.codehaus.gmavenplus.version}</version>
                 <executions>
                     <execution>
                         <id>1</id>
diff --git a/examples/open-tracing/pom.xml b/examples/open-tracing/pom.xml
index 21f246e..cc01f99 100644
--- a/examples/open-tracing/pom.xml
+++ b/examples/open-tracing/pom.xml
@@ -52,7 +52,17 @@
         <dependency>
             <groupId>com.uber.jaeger</groupId>
             <artifactId>jaeger-core</artifactId>
-            <version>0.20.0</version>
+            <version>${com.uber.jaeger.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-api</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.httpcomponents</groupId>
+                    <artifactId>httpcore</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
 
 
diff --git a/ext/cdi/jersey-weld2-se/pom.xml b/ext/cdi/jersey-weld2-se/pom.xml
index 17e5f20..18eddfb 100644
--- a/ext/cdi/jersey-weld2-se/pom.xml
+++ b/ext/cdi/jersey-weld2-se/pom.xml
@@ -36,6 +36,12 @@
         <dependency>
             <groupId>org.jboss.weld.se</groupId>
             <artifactId>weld-se-core</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>jakarta.interceptor</groupId>
+                    <artifactId>jakarta.interceptor-api</artifactId>
+                </exclusion>
+            </exclusions>
             <scope>provided</scope>
         </dependency>
         <dependency>
@@ -51,6 +57,12 @@
         <dependency>
             <groupId>jakarta.enterprise</groupId>
             <artifactId>jakarta.enterprise.cdi-api</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>jakarta.interceptor</groupId>
+                    <artifactId>jakarta.interceptor-api</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
     </dependencies>
 
diff --git a/ext/mvc-mustache/pom.xml b/ext/mvc-mustache/pom.xml
index 8a14f5c..c409a7c 100644
--- a/ext/mvc-mustache/pom.xml
+++ b/ext/mvc-mustache/pom.xml
@@ -66,6 +66,17 @@
             <groupId>com.github.spullara.mustache.java</groupId>
             <artifactId>compiler</artifactId>
             <version>${mustache.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.google.guava</groupId>
+                    <artifactId>guava</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>${guava.version}</version>
         </dependency>
     </dependencies>
 
diff --git a/ext/rx/rx-client-rxjava2/pom.xml b/ext/rx/rx-client-rxjava2/pom.xml
index d0f8bb2..f859654 100644
--- a/ext/rx/rx-client-rxjava2/pom.xml
+++ b/ext/rx/rx-client-rxjava2/pom.xml
@@ -42,11 +42,17 @@
             <groupId>io.reactivex.rxjava2</groupId>
             <artifactId>rxjava</artifactId>
             <version>${rxjava2.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.reactivestreams</groupId>
+                    <artifactId>reactive-streams</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
         <dependency>
             <groupId>org.reactivestreams</groupId>
             <artifactId>reactive-streams</artifactId>
-            <version>1.0.0</version>
+            <version>${reactive.streams.version}</version>
         </dependency>
     </dependencies>
 </project>
diff --git a/ext/spring6/pom.xml b/ext/spring6/pom.xml
index 2cfbff6..4f28e94 100644
--- a/ext/spring6/pom.xml
+++ b/ext/spring6/pom.xml
@@ -89,6 +89,12 @@
             <groupId>org.glassfish.hk2</groupId>
             <artifactId>hk2</artifactId>
             <version>${hk2.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.ow2.asm</groupId>
+                    <artifactId>asm</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
 
         <dependency>
diff --git a/incubator/html-json/pom.xml b/incubator/html-json/pom.xml
index 086d6e3..3ad5b9e 100644
--- a/incubator/html-json/pom.xml
+++ b/incubator/html-json/pom.xml
@@ -40,6 +40,7 @@
 
     <properties>
         <net.java.html.version>1.5.1</net.java.html.version>
+        <enforcer.skip>true</enforcer.skip>
     </properties>
 
     <dependencies>
diff --git a/incubator/kryo/pom.xml b/incubator/kryo/pom.xml
index 7c09b33..36b1f1b 100644
--- a/incubator/kryo/pom.xml
+++ b/incubator/kryo/pom.xml
@@ -48,6 +48,17 @@
         <dependency>
             <groupId>com.esotericsoftware</groupId>
             <artifactId>kryo</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.ow2.asm</groupId>
+                    <artifactId>asm</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.ow2.asm</groupId>
+            <artifactId>asm</artifactId>
+            <version>${asm.version}</version>
         </dependency>
 
         <dependency>
diff --git a/inject/hk2/pom.xml b/inject/hk2/pom.xml
index fd0875b..0f9eacb 100644
--- a/inject/hk2/pom.xml
+++ b/inject/hk2/pom.xml
@@ -51,6 +51,10 @@
                     <groupId>org.javassist</groupId>
                     <artifactId>javassist</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>jakarta.inject</groupId>
+                    <artifactId>jakarta.inject-api</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
 
diff --git a/media/json-gson/pom.xml b/media/json-gson/pom.xml
new file mode 100644
index 0000000..8b2c2c5
--- /dev/null
+++ b/media/json-gson/pom.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 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
+    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
+
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.glassfish.jersey.media</groupId>
+        <artifactId>project</artifactId>
+        <version>3.1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>jersey-media-json-gson</artifactId>
+    <packaging>jar</packaging>
+    <name>jersey-media-json-gson</name>
+
+    <description>
+        Jersey GSON support module.
+    </description>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>com.sun.istack</groupId>
+                <artifactId>istack-commons-maven-plugin</artifactId>
+                <inherited>true</inherited>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <inherited>true</inherited>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <inherited>true</inherited>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Export-Package>org.glassfish.jersey.gson.*</Export-Package>
+                        <Import-Package>${javax.annotation.osgi.version},*</Import-Package>
+                    </instructions>
+                    <unpackBundle>true</unpackBundle>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/media/json-gson/src/main/java/org/glassfish/jersey/gson/JsonGsonFeature.java b/media/json-gson/src/main/java/org/glassfish/jersey/gson/JsonGsonFeature.java
new file mode 100644
index 0000000..498f958
--- /dev/null
+++ b/media/json-gson/src/main/java/org/glassfish/jersey/gson/JsonGsonFeature.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 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
+ * 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.gson;
+
+import jakarta.ws.rs.core.Configuration;
+import jakarta.ws.rs.core.Feature;
+import jakarta.ws.rs.core.FeatureContext;
+
+import org.glassfish.jersey.CommonProperties;
+import org.glassfish.jersey.gson.internal.JsonGsonAutoDiscoverable;
+import org.glassfish.jersey.gson.internal.JsonGsonProvider;
+import org.glassfish.jersey.internal.InternalProperties;
+import org.glassfish.jersey.internal.util.PropertiesHelper;
+/**
+ * Feature used to register Gson providers.
+ * <p>
+ * The Feature is automatically enabled when {@link JsonGsonAutoDiscoverable} is on classpath.
+ * Default GSON configuration obtained by calling {@code GsonBuilder.create()} is used.
+ * <p>
+ * Custom configuration, if required, can be achieved by implementing custom {@link jakarta.ws.rs.ext.ContextResolver} and
+ * registering it as a provider into JAX-RS runtime:
+ * <pre>
+ * &#64;Provider
+ * &#64;class GsonContextResolver implements ContextResolver&lt;Gson&gt; {
+ *      &#64;Override
+ *      public Gson getContext(Class<?> type) {
+ *          GsonBuilder builder = new GsonBuilder();
+ *          // add custom configuration
+ *          return builder.create();
+ *      }
+ * }
+ * </pre>
+ *
+ */
+public class JsonGsonFeature implements Feature {
+
+    private static final String JSON_FEATURE = JsonGsonFeature.class.getSimpleName();
+
+    @Override
+    public boolean configure(final FeatureContext context) {
+        final Configuration config = context.getConfiguration();
+
+        final String jsonFeature = CommonProperties.getValue(
+                config.getProperties(),
+                config.getRuntimeType(),
+                InternalProperties.JSON_FEATURE, JSON_FEATURE, String.class);
+
+        // Other JSON providers registered.
+        if (!JSON_FEATURE.equalsIgnoreCase(jsonFeature)) {
+            return false;
+        }
+
+        // Disable other JSON providers.
+        context.property(PropertiesHelper.getPropertyNameForRuntime(
+                InternalProperties.JSON_FEATURE, config.getRuntimeType()), JSON_FEATURE);
+
+        context.register(JsonGsonProvider.class);
+
+        return true;
+    }
+}
diff --git a/media/json-gson/src/main/java/org/glassfish/jersey/gson/internal/JsonGsonAutoDiscoverable.java b/media/json-gson/src/main/java/org/glassfish/jersey/gson/internal/JsonGsonAutoDiscoverable.java
new file mode 100644
index 0000000..f532953
--- /dev/null
+++ b/media/json-gson/src/main/java/org/glassfish/jersey/gson/internal/JsonGsonAutoDiscoverable.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 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
+ * 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.gson.internal;
+
+import jakarta.annotation.Priority;
+import jakarta.ws.rs.core.FeatureContext;
+
+import org.glassfish.jersey.gson.JsonGsonFeature;
+import org.glassfish.jersey.internal.spi.AutoDiscoverable;
+import org.glassfish.jersey.internal.spi.ForcedAutoDiscoverable;
+
+/**
+ * {@link ForcedAutoDiscoverable} registering {@link JsonGsonFeature} if the feature is not already registered.
+ * <p>
+ *
+ * @see JsonGsonFeature
+ */
+@Priority(AutoDiscoverable.DEFAULT_PRIORITY)
+public class JsonGsonAutoDiscoverable implements ForcedAutoDiscoverable {
+
+    @Override
+    public void configure(FeatureContext context) {
+        if (!context.getConfiguration().isRegistered(JsonGsonFeature.class)) {
+            context.register(JsonGsonFeature.class);
+        }
+    }
+}
diff --git a/media/json-gson/src/main/java/org/glassfish/jersey/gson/internal/JsonGsonProvider.java b/media/json-gson/src/main/java/org/glassfish/jersey/gson/internal/JsonGsonProvider.java
new file mode 100644
index 0000000..a35dfad
--- /dev/null
+++ b/media/json-gson/src/main/java/org/glassfish/jersey/gson/internal/JsonGsonProvider.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 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
+ * 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.gson.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.ProcessingException;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.core.NoContentException;
+import jakarta.ws.rs.ext.ContextResolver;
+import jakarta.ws.rs.ext.Provider;
+import jakarta.ws.rs.ext.Providers;
+
+import org.glassfish.jersey.gson.LocalizationMessages;
+import org.glassfish.jersey.message.internal.AbstractMessageReaderWriterProvider;
+import org.glassfish.jersey.message.internal.EntityInputStream;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+/**
+ * Entity provider (reader and writer) for Gson.
+ *
+ */
+@Provider
+@Produces({"application/json", "text/json", "*/*"})
+@Consumes({"application/json", "text/json", "*/*"})
+public class JsonGsonProvider extends AbstractMessageReaderWriterProvider<Object> {
+
+    private static final String JSON = "json";
+    private static final String PLUS_JSON = "+json";
+
+    private Providers providers;
+
+    public JsonGsonProvider(@Context Providers providers) {
+        this.providers = providers;
+    }
+
+    @Override
+    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+        return supportsMediaType(mediaType);
+    }
+
+    @Override
+    public Object readFrom(Class<Object> type, Type genericType,
+                           Annotation[] annotations,
+                           MediaType mediaType,
+                           MultivaluedMap<String, String> httpHeaders,
+                           InputStream entityStream) throws IOException, WebApplicationException {
+        EntityInputStream entityInputStream =  new EntityInputStream(entityStream);
+        entityStream = entityInputStream;
+        if (entityInputStream.isEmpty()) {
+            throw new NoContentException(LocalizationMessages.ERROR_GSON_EMPTYSTREAM());
+        }
+        Gson gson = getGson(type);
+        try {
+            return gson.fromJson(new InputStreamReader(entityInputStream,
+                    AbstractMessageReaderWriterProvider.getCharset(mediaType)), genericType);
+        } catch (Exception e) {
+            throw new ProcessingException(LocalizationMessages.ERROR_GSON_DESERIALIZATION(), e);
+        }
+    }
+
+    @Override
+    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+        return supportsMediaType(mediaType);
+    }
+
+    @Override
+    public void writeTo(Object o, Class<?> type, Type genericType,
+                        Annotation[] annotations,
+                        MediaType mediaType,
+                        MultivaluedMap<String, Object> httpHeaders,
+                        OutputStream entityStream) throws IOException, WebApplicationException {
+        Gson gson = getGson(type);
+        try {
+            entityStream.write(gson.toJson(o).getBytes(AbstractMessageReaderWriterProvider.getCharset(mediaType)));
+            entityStream.flush();
+        } catch (Exception e) {
+            throw new ProcessingException(LocalizationMessages.ERROR_GSON_SERIALIZATION(), e);
+        }
+    }
+
+    private Gson getGson(Class<?> type) {
+        final ContextResolver<Gson> contextResolver = providers.getContextResolver(Gson.class, MediaType.APPLICATION_JSON_TYPE);
+        if (contextResolver != null) {
+            return contextResolver.getContext(type);
+        } else {
+            return GsonSingleton.INSTANCE.getInstance();
+        }
+    }
+
+    /**
+     * @return true for all media types of the pattern *&#47;json and
+     * *&#47;*+json.
+     */
+    private static boolean supportsMediaType(final MediaType mediaType) {
+        return mediaType.getSubtype().equals(JSON) || mediaType.getSubtype().endsWith(PLUS_JSON);
+    }
+
+    private enum GsonSingleton {
+        INSTANCE;
+
+        // Thread-safe
+        private Gson gsonInstance;
+
+        Gson getInstance() {
+            return gsonInstance;
+        }
+
+        GsonSingleton() {
+            this.gsonInstance = new GsonBuilder().create();
+        }
+    }
+}
diff --git a/media/json-gson/src/main/java/org/glassfish/jersey/gson/package-info.java b/media/json-gson/src/main/java/org/glassfish/jersey/gson/package-info.java
new file mode 100644
index 0000000..12e6b90
--- /dev/null
+++ b/media/json-gson/src/main/java/org/glassfish/jersey/gson/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 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
+ * 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
+ */
+
+/**
+ * Jersey classes supporting JSON marshalling and unmarshalling using GSON.
+ */
+package org.glassfish.jersey.gson;
diff --git a/media/json-gson/src/main/resources/META-INF/services/org.glassfish.jersey.internal.spi.ForcedAutoDiscoverable b/media/json-gson/src/main/resources/META-INF/services/org.glassfish.jersey.internal.spi.ForcedAutoDiscoverable
new file mode 100644
index 0000000..7f4e0ee
--- /dev/null
+++ b/media/json-gson/src/main/resources/META-INF/services/org.glassfish.jersey.internal.spi.ForcedAutoDiscoverable
@@ -0,0 +1 @@
+org.glassfish.jersey.gson.internal.JsonGsonAutoDiscoverable
diff --git a/media/json-gson/src/main/resources/org/glassfish/jersey/gson/localization.properties b/media/json-gson/src/main/resources/org/glassfish/jersey/gson/localization.properties
new file mode 100644
index 0000000..b2ea26a
--- /dev/null
+++ b/media/json-gson/src/main/resources/org/glassfish/jersey/gson/localization.properties
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 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
+# 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
+#
+
+error.gson.serialization=Error writing GSON serialized object.
+error.gson.deserialization=Error deserializing object from entity stream.
+error.gson.emptystream=GSON cannot parse empty input stream.
diff --git a/media/json-gson/src/test/java/org/glassfish/jersey/gson/internal/JsonGsonProviderTest.java b/media/json-gson/src/test/java/org/glassfish/jersey/gson/internal/JsonGsonProviderTest.java
new file mode 100644
index 0000000..7aa403e
--- /dev/null
+++ b/media/json-gson/src/test/java/org/glassfish/jersey/gson/internal/JsonGsonProviderTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 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
+ * 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.gson.internal;
+
+import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.MultivaluedHashMap;
+import jakarta.ws.rs.core.NoContentException;
+import jakarta.ws.rs.ext.ContextResolver;
+import jakarta.ws.rs.ext.ExceptionMapper;
+import jakarta.ws.rs.ext.MessageBodyReader;
+import jakarta.ws.rs.ext.MessageBodyWriter;
+import jakarta.ws.rs.ext.Providers;
+
+import org.junit.Test;
+
+public class JsonGsonProviderTest {
+
+    @Test(expected = NoContentException.class)
+    public void shouldThrowNoContentException() throws IOException {
+        Providers providers = new EmptyProviders();
+        MessageBodyReader<Foo> mbr = (MessageBodyReader) new JsonGsonProvider(providers);
+        mbr.readFrom(Foo.class, Foo.class, new Annotation[0], APPLICATION_JSON_TYPE,
+                new MultivaluedHashMap<>(), new ByteArrayInputStream(new byte[0]));
+    }
+
+    private static final class Foo {
+        // no members
+    }
+
+    private static final class EmptyProviders implements Providers {
+
+        @Override
+        public final <T> MessageBodyReader<T> getMessageBodyReader(final Class<T> type, final Type genericType,
+                final Annotation[] annotations, final MediaType mediaType) {
+            return null;
+        }
+
+        @Override
+        public final <T> MessageBodyWriter<T> getMessageBodyWriter(final Class<T> type, final Type genericType,
+                final Annotation[] annotations, final MediaType mediaType) {
+            return null;
+        }
+
+        @Override
+        public final <T extends Throwable> ExceptionMapper<T> getExceptionMapper(final Class<T> type) {
+            return null;
+        }
+
+        @Override
+        public final <T> ContextResolver<T> getContextResolver(final Class<T> contextType, final MediaType mediaType) {
+            return null;
+        }
+
+    }
+
+}
diff --git a/media/pom.xml b/media/pom.xml
index 68daa76..e738eb1 100644
--- a/media/pom.xml
+++ b/media/pom.xml
@@ -38,6 +38,7 @@
     <modules>
         <module>jaxb</module>
         <module>json-binding</module>
+        <module>json-gson</module>
         <module>json-jackson</module>
         <module>json-jettison</module>
         <module>json-processing</module>
diff --git a/pom.xml b/pom.xml
index c010f31..e66d89d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -236,7 +236,7 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-enforcer-plugin</artifactId>
-                    <version>3.0.0-M2</version>
+                    <version>${enforcer.version}</version>
                     <executions>
                         <execution>
                             <id>enforce-versions</id>
@@ -248,6 +248,7 @@
                                     <requireJavaVersion>
                                         <version>${java.version}</version>
                                     </requireJavaVersion>
+                                    <dependencyConvergence/>
                                 </rules>
                             </configuration>
                         </execution>
@@ -2063,6 +2064,12 @@
             </dependency>
 
             <dependency>
+               <groupId>com.google.code.gson</groupId>
+               <artifactId>gson</artifactId>
+               <version>${gson.version}</version>
+            </dependency>
+
+            <dependency>
                 <groupId>io.opentracing</groupId>
                 <artifactId>opentracing-api</artifactId>
                 <version>${opentracing.version}</version>
@@ -2124,6 +2131,15 @@
         <freemarker.version>2.3.27-incubating</freemarker.version>
         <gae.version>1.9.59</gae.version>
         <grizzly.client.version>1.16</grizzly.client.version>
+        <enforcer.version>3.1.0</enforcer.version>
+
+        <!--versions, extracted here due to maven-enforcer-plugin -->
+        <slf4j.version>2.0.0-alpha6</slf4j.version>
+        <commons.codec.version>1.15</commons.codec.version>
+        <reactive.streams.version>1.0.3</reactive.streams.version>
+        <com.uber.jaeger.version>0.27.0</com.uber.jaeger.version>
+        <org.codehaus.gmavenplus.version>1.13.1</org.codehaus.gmavenplus.version>
+        <!-- end of versions extracted here due to maven-enforcer-plugin -->
 
         <!-- microprofile -->
         <microprofile.config.version>3.0</microprofile.config.version>
@@ -2148,7 +2164,7 @@
         <jmh.version>1.10.2</jmh.version>
         <jmockit.version>1.44</jmockit.version>
         <junit5.version>5.6.0</junit5.version>
-        <kryo.version>4.0.1</kryo.version>
+        <kryo.version>4.0.2</kryo.version>
         <mockito.version>3.9.0</mockito.version> <!-- CQ 17673 -->
         <mustache.version>0.8.17</mustache.version>
         <netty.version>4.1.75.Final</netty.version>
@@ -2169,9 +2185,9 @@
 
         <simple.version>6.0.1</simple.version>
         <skip.e2e>false</skip.e2e>
-        <slf4j.version>1.7.21</slf4j.version>
         <spring6.version>6.0.0-M3</spring6.version>
         <surefire.version>3.0.0-M6</surefire.version>
+        <gson.version>2.9.0</gson.version>
 
         <!-- Jakartified, eligible for CQ -->
         <weld.version>5.0.0.SP2</weld.version>
diff --git a/test-framework/maven/container-runner-maven-plugin/pom.xml b/test-framework/maven/container-runner-maven-plugin/pom.xml
index 1f75a57..710dab3 100644
--- a/test-framework/maven/container-runner-maven-plugin/pom.xml
+++ b/test-framework/maven/container-runner-maven-plugin/pom.xml
@@ -36,9 +36,9 @@
     </description>
 
     <properties>
-        <groovy.version>3.0.2</groovy.version>
-        <groovy-eclipse-compiler.version>3.6.0-03</groovy-eclipse-compiler.version>
-        <groovy-eclipse-batch.version>3.0.2-02</groovy-eclipse-batch.version>
+        <groovy.version>3.0.9</groovy.version>
+        <groovy-eclipse-compiler.version>3.7.0</groovy-eclipse-compiler.version>
+        <groovy-eclipse-batch.version>3.0.8-01</groovy-eclipse-batch.version>
         <maven.version>3.6.0</maven.version>
         <maven-plugin.version>3.6.0</maven-plugin.version>
     </properties>
@@ -49,6 +49,28 @@
             <groupId>org.apache.maven</groupId>
             <artifactId>maven-core</artifactId>
             <version>${maven.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.codehaus.plexus</groupId>
+                    <artifactId>plexus-component-annotations</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.codehaus.plexus</groupId>
+                    <artifactId>plexus-utils</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.codehaus.plexus</groupId>
+                    <artifactId>plexus-container-default</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.sonatype.plexus</groupId>
+                    <artifactId>plexus-sec-dispatcher</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>com.google.code.findbugs</groupId>
+                    <artifactId>jsr305</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
         <dependency>
             <groupId>org.apache.maven</groupId>
@@ -59,6 +81,12 @@
             <groupId>org.apache.maven</groupId>
             <artifactId>maven-plugin-api</artifactId>
             <version>${maven.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.codehaus.plexus</groupId>
+                    <artifactId>plexus-utils</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
         <dependency>
             <groupId>org.apache.maven</groupId>
@@ -89,16 +117,31 @@
         </dependency>
 
         <dependency>
-            <groupId>org.apache.maven</groupId>
-            <artifactId>maven-project</artifactId>
-            <version>2.2.1</version>
-            <scope>provided</scope>
-        </dependency>
-
-        <dependency>
             <groupId>org.codehaus.gmavenplus</groupId>
             <artifactId>gmavenplus-plugin</artifactId>
-            <version>1.7.0</version>
+            <version>${org.codehaus.gmavenplus.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.maven.shared</groupId>
+                    <artifactId>file-management</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.maven</groupId>
+                    <artifactId>maven-model</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.maven</groupId>
+                    <artifactId>maven-core</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.maven</groupId>
+                    <artifactId>maven-plugin-api</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.maven</groupId>
+                    <artifactId>maven-artifact</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
 
         <dependency>
@@ -111,6 +154,16 @@
             <artifactId>groovy-all</artifactId>
             <type>pom</type>
             <version>${groovy.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.ant</groupId>
+                    <artifactId>ant-launcher</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.ant</groupId>
+                    <artifactId>ant</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
 
         <dependency>
diff --git a/test-framework/maven/custom-enforcer-rules/pom.xml b/test-framework/maven/custom-enforcer-rules/pom.xml
index 909d37d..454813d 100644
--- a/test-framework/maven/custom-enforcer-rules/pom.xml
+++ b/test-framework/maven/custom-enforcer-rules/pom.xml
@@ -34,12 +34,32 @@
         <dependency>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-enforcer-plugin</artifactId>
-            <version>1.4.1</version>
+            <version>${enforcer.version}</version>
             <exclusions>
                 <exclusion>
                     <groupId>junit</groupId>
                     <artifactId>junit</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>org.codehaus.plexus</groupId>
+                    <artifactId>plexus-classworlds</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.codehaus.plexus</groupId>
+                    <artifactId>plexus-utils</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>commons-io</groupId>
+                    <artifactId>commons-io</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.maven</groupId>
+                    <artifactId>maven-core</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.eclipse.aether</groupId>
+                    <artifactId>aether-util</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
 
diff --git a/tests/e2e-client/pom.xml b/tests/e2e-client/pom.xml
index e58048f..729a433 100644
--- a/tests/e2e-client/pom.xml
+++ b/tests/e2e-client/pom.xml
@@ -187,6 +187,11 @@
             <artifactId>xmlunit</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>${commons.io.version}</version>
+        </dependency>
     </dependencies>
 
     <profiles>
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/ChunkedInputStreamClosedPrematurelyTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/ChunkedInputStreamClosedPrematurelyTest.java
index 33b1fbb..3298e5d 100644
--- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/ChunkedInputStreamClosedPrematurelyTest.java
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/ChunkedInputStreamClosedPrematurelyTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -22,6 +22,7 @@
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.util.Arrays;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ExecutionException;
@@ -57,8 +58,6 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import com.google.common.util.concurrent.SettableFuture;
-
 /**
  * Reproducer for JERSEY-2705. Client side entity InputStream exception
  * in chunked mode should not lead to the same behavior on the server side,
@@ -80,7 +79,7 @@
     @SuppressWarnings({"ThrowableResultOfMethodCallIgnored", "JavaDoc"})
     public static class TestResource {
 
-        private static final ConcurrentMap<String, SettableFuture<Exception>> REQUEST_MAP = new ConcurrentHashMap<>();
+        private static final ConcurrentMap<String, CompletableFuture<Exception>> REQUEST_MAP = new ConcurrentHashMap<>();
 
         @QueryParam(REQ_ID_PARAM_NAME)
         private String reqId;
@@ -100,7 +99,7 @@
                 thrown = ex;
             }
 
-            if (!getFutureFor(reqId).set(thrown)) {
+            if (!getFutureFor(reqId).complete(thrown)) {
                 LOGGER.log(Level.WARNING,
                         "Unable to set stream processing exception into the settable future instance for request id " + reqId,
                         thrown);
@@ -113,7 +112,7 @@
         @GET
         public Boolean getRequestWasMade() {
             // add a new future for the request if not there yet to avoid race conditions with POST processing
-            final SettableFuture<Exception> esf = getFutureFor(reqId);
+            final CompletableFuture<Exception> esf = getFutureFor(reqId);
             try {
                 // wait for up to three second for a request to be made;
                 // there is always a value, if set...
@@ -126,7 +125,7 @@
         @Path("/requestCausedException")
         @GET
         public Boolean getRequestCausedException() {
-            final SettableFuture<Exception> esf = getFutureFor(reqId);
+            final CompletableFuture<Exception> esf = getFutureFor(reqId);
             try {
                 return esf.get(3, TimeUnit.SECONDS) != NO_EXCEPTION;
             } catch (InterruptedException | ExecutionException | TimeoutException e) {
@@ -134,9 +133,9 @@
             }
         }
 
-        private SettableFuture<Exception> getFutureFor(String key) {
-            final SettableFuture<Exception> esf = SettableFuture.create();
-            final SettableFuture<Exception> oldEsf = REQUEST_MAP.putIfAbsent(key, esf);
+        private CompletableFuture<Exception> getFutureFor(String key) {
+            final CompletableFuture<Exception> esf = new CompletableFuture();
+            final CompletableFuture<Exception> oldEsf = REQUEST_MAP.putIfAbsent(key, esf);
             return (oldEsf != null) ? oldEsf : esf;
         }
     }
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxySelectorTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxySelectorTest.java
index 1741a66..91ea1b1 100644
--- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxySelectorTest.java
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxySelectorTest.java
@@ -61,9 +61,8 @@
     @Parameterized.Parameters(name = "{index}: {0}")
     public static List<Object[]> testData() {
         return Arrays.asList(new Object[][]{
-//                {ApacheConnectorProvider.class},
-//                {Apache5ConnectorProvider.class},
-//                {JettyConnectorProvider.class},
+                // Apache, Grizzly, Jetty have the proxy set on constructor, i.e. ProxySelector cannot choose based on URI.
+                // HttpUrlConnector ignores proxy on localhost.
                 {NettyConnectorProvider.class},
         });
     }
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxyTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxyTest.java
index 1ae437b..f3006e2 100644
--- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxyTest.java
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/proxy/ProxyTest.java
@@ -25,7 +25,9 @@
 import org.glassfish.jersey.apache5.connector.Apache5ConnectorProvider;
 import org.glassfish.jersey.client.ClientConfig;
 import org.glassfish.jersey.client.ClientProperties;
+import org.glassfish.jersey.client.HttpUrlConnectorProvider;
 import org.glassfish.jersey.client.spi.ConnectorProvider;
+import org.glassfish.jersey.grizzly.connector.GrizzlyConnectorProvider;
 import org.glassfish.jersey.jetty.connector.JettyConnectorProvider;
 import org.glassfish.jersey.netty.connector.NettyConnectorProvider;
 import org.junit.AfterClass;
@@ -70,8 +72,10 @@
         return Arrays.asList(new Object[][]{
                 {ApacheConnectorProvider.class},
                 {Apache5ConnectorProvider.class},
+                {GrizzlyConnectorProvider.class},
                 {JettyConnectorProvider.class},
                 {NettyConnectorProvider.class},
+                {HttpUrlConnectorProvider.class},
         });
     }
 
@@ -96,9 +100,11 @@
 
     @Test
     public void testGet407() {
+        // Grizzly sends (String)null password and username
+        int expected = GrizzlyConnectorProvider.class.isInstance(connectorProvider) ? 400 : 407;
         client().property(ClientProperties.PROXY_URI, ProxyTest.PROXY_URI);
         try (Response response = target("proxyTest").request().get()) {
-            assertEquals(407, response.getStatus());
+            assertEquals(expected, response.getStatus());
         } catch (ProcessingException pe) {
             Assert.assertTrue(pe.getMessage().contains("407")); // netty
         }
@@ -110,7 +116,8 @@
         client().property(ClientProperties.PROXY_USERNAME, ProxyTest.PROXY_USERNAME);
         client().property(ClientProperties.PROXY_PASSWORD, ProxyTest.PROXY_PASSWORD);
         Response response = target("proxyTest").request().get();
-        assertEquals(200, response.getStatus());
+        response.bufferEntity();
+        assertEquals(response.readEntity(String.class), 200, response.getStatus());
     }
 
     private static Server server;
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/AbstractConnectorServerTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/AbstractConnectorServerTest.java
index 79d944d..8219d6b 100644
--- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/AbstractConnectorServerTest.java
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/AbstractConnectorServerTest.java
@@ -37,7 +37,7 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
-import com.google.common.io.ByteStreams;
+import org.apache.commons.io.IOUtils;
 
 /**
  * SSL connector hostname verification tests.
@@ -101,9 +101,9 @@
         final InputStream trustStore = SslConnectorConfigurationTest.class.getResourceAsStream(clientTrustStore());
         final InputStream keyStore = SslConnectorConfigurationTest.class.getResourceAsStream(CLIENT_KEY_STORE);
         return SslConfigurator.newInstance()
-                .trustStoreBytes(ByteStreams.toByteArray(trustStore))
+                .trustStoreBytes(IOUtils.toByteArray(trustStore))
                 .trustStorePassword("asdfgh")
-                .keyStoreBytes(ByteStreams.toByteArray(keyStore))
+                .keyStoreBytes(IOUtils.toByteArray(keyStore))
                 .keyPassword("asdfgh")
                 .createSSLContext();
     }
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/Server.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/Server.java
index c986c2c..20795c3 100644
--- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/Server.java
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/connector/ssl/Server.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -23,6 +23,7 @@
 
 import jakarta.ws.rs.core.UriBuilder;
 
+import org.apache.commons.io.IOUtils;
 import org.glassfish.jersey.logging.LoggingFeature;
 import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
 import org.glassfish.jersey.server.ResourceConfig;
@@ -31,8 +32,6 @@
 import org.glassfish.grizzly.ssl.SSLContextConfigurator;
 import org.glassfish.grizzly.ssl.SSLEngineConfigurator;
 
-import com.google.common.io.ByteStreams;
-
 /**
  * A simple SSL-secured HTTP server for testing purposes.
  *
@@ -87,9 +86,9 @@
         SSLContextConfigurator sslContext = new SSLContextConfigurator();
 
         // set up security context
-        sslContext.setKeyStoreBytes(ByteStreams.toByteArray(keyStore));  // contains server key pair
+        sslContext.setKeyStoreBytes(IOUtils.toByteArray(keyStore));  // contains server key pair
         sslContext.setKeyStorePass("asdfgh");
-        sslContext.setTrustStoreBytes(ByteStreams.toByteArray(trustStore)); // contains client certificate
+        sslContext.setTrustStoreBytes(IOUtils.toByteArray(trustStore)); // contains client certificate
         sslContext.setTrustStorePass("asdfgh");
 
         ResourceConfig rc = new ResourceConfig();
diff --git a/tests/e2e-server/pom.xml b/tests/e2e-server/pom.xml
index aca4fa5..51408e2 100644
--- a/tests/e2e-server/pom.xml
+++ b/tests/e2e-server/pom.xml
@@ -95,6 +95,11 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>org.glassfish.jersey.media</groupId>
+            <artifactId>jersey-media-json-gson</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.glassfish.jersey.ext</groupId>
             <artifactId>jersey-bean-validation</artifactId>
             <scope>test</scope>
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/GsonCustomTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/GsonCustomTest.java
new file mode 100644
index 0000000..a967dc7
--- /dev/null
+++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/GsonCustomTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 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
+ * 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.Assert.assertEquals;
+
+import java.util.Date;
+
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.ext.ContextResolver;
+import jakarta.ws.rs.ext.Provider;
+
+import org.glassfish.jersey.gson.JsonGsonFeature;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.Test;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+public class GsonCustomTest extends JerseyTest {
+
+    private static final Date date = new Date(0);
+
+    @Path("/test")
+    public static class Resource {
+
+        @GET
+        @Consumes("application/json")
+        public Date get() {
+            return date;
+        }
+    }
+
+    @Override
+    protected Application configure() {
+        return new ResourceConfig(Resource.class).register(JsonGsonFeature.class).register(GsonContextResolver.class);
+    }
+
+    @Test
+    public void get() {
+        Response response = target("/test").request().get();
+        assertEquals(200, response.getStatus());
+        String obj = response.readEntity(String.class);
+        assertEquals("\"1970\"", obj);
+    }
+
+    @Provider
+    public static class GsonContextResolver implements ContextResolver<Gson> {
+        @Override
+        public Gson getContext(Class<?> type) {
+            GsonBuilder builder = new GsonBuilder();
+            builder.setDateFormat("yyyy");
+            return builder.create();
+        }
+    }
+}
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/GsonDefaultTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/GsonDefaultTest.java
new file mode 100644
index 0000000..0d0dad5
--- /dev/null
+++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/GsonDefaultTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 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
+ * 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.Assert.assertEquals;
+
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.Response;
+
+import org.glassfish.jersey.client.ClientConfig;
+import org.glassfish.jersey.gson.JsonGsonFeature;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.Test;
+
+public class GsonDefaultTest extends JerseyTest {
+
+    @Path("/test")
+    public static class Resource {
+
+        @POST
+        @Consumes("application/json")
+        @Produces("application/json")
+        public Obj post(Obj entity) {
+            entity.setValue("bar");
+            return entity;
+        }
+
+        @GET
+        @Consumes("application/json")
+        public Obj get() {
+            Obj entity = new Obj();
+            entity.setValue("get");
+            return entity;
+        }
+    }
+
+    @Override
+    protected Application configure() {
+        return new ResourceConfig(Resource.class)
+                .register(JsonGsonFeature.class);
+    }
+
+    @Override
+    protected void configureClient(ClientConfig config) {
+        config.register(JsonGsonFeature.class);
+    }
+
+    @Test
+    public void get() {
+        Response response = target("/test").request().get();
+        assertEquals(200, response.getStatus());
+        Obj obj = response.readEntity(Obj.class);
+        assertEquals("get", obj.getValue());
+    }
+
+    @Test
+    public void post() {
+        Obj obj = new Obj();
+        obj.setValue("foo");
+        Response response = target("/test").request().post(Entity.json(obj));
+        assertEquals(200, response.getStatus());
+        obj = response.readEntity(Obj.class);
+        assertEquals("bar", obj.getValue());
+    }
+
+    public static class Obj {
+        private String value;
+
+        public String getValue() {
+            return value;
+        }
+        public void setValue(String value) {
+            this.value = value;
+        }
+    }
+}
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlBeanParamTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlBeanParamTest.java
index 481c20c..98965c9 100644
--- a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlBeanParamTest.java
+++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlBeanParamTest.java
@@ -22,7 +22,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-import java.util.Properties;
+import java.util.Collections;
 
 import jakarta.ws.rs.BeanParam;
 import jakarta.ws.rs.CookieParam;
@@ -66,8 +66,6 @@
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 
-import com.google.common.collect.ImmutableMap;
-
 /**
  * Tests whether WADL for a {@link BeanParam} annotated resource method parameter is generated properly.
  * <p/>
@@ -174,7 +172,7 @@
                                 XPathConstants.NODE))
         );
         XMLUnit.setXpathNamespaceContext(
-                new SimpleNamespaceContext(ImmutableMap.of("wadl", "http://wadl.dev.java.net/2009/02")));
+                new SimpleNamespaceContext(Collections.singletonMap("wadl", "http://wadl.dev.java.net/2009/02")));
         diff.overrideElementQualifier(elementQualifier);
         XMLAssert.assertXMLEqual(diff, true);
     }
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlResourceTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlResourceTest.java
index da2d787..1729036 100644
--- a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlResourceTest.java
+++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlResourceTest.java
@@ -27,6 +27,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.net.URI;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -112,8 +113,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import com.google.common.collect.ImmutableMap;
-
 import com.sun.research.ws.wadl.Method;
 import com.sun.research.ws.wadl.Param;
 import com.sun.research.ws.wadl.Request;
@@ -1284,7 +1283,7 @@
                                     XPathConstants.NODE))
             );
             XMLUnit.setXpathNamespaceContext(
-                    new SimpleNamespaceContext(ImmutableMap.of("wadl", "http://wadl.dev.java.net/2009/02")));
+                    new SimpleNamespaceContext(Collections.singletonMap("wadl", "http://wadl.dev.java.net/2009/02")));
             final ElementQualifier elementQualifier = new RecursiveElementNameAndTextQualifier();
             diff.overrideElementQualifier(elementQualifier);
             XMLAssert.assertXMLEqual(diff, true);
diff --git a/tests/integration/externalproperties/src/test/java/org/glassfish/jersey/tests/externalproperties/HttpProxyTest.java b/tests/integration/externalproperties/src/test/java/org/glassfish/jersey/tests/externalproperties/HttpProxyTest.java
index 10a5703..7e79571 100644
--- a/tests/integration/externalproperties/src/test/java/org/glassfish/jersey/tests/externalproperties/HttpProxyTest.java
+++ b/tests/integration/externalproperties/src/test/java/org/glassfish/jersey/tests/externalproperties/HttpProxyTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 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
diff --git a/tests/integration/j-376/pom.xml b/tests/integration/j-376/pom.xml
index a6c1535..935cd8f 100644
--- a/tests/integration/j-376/pom.xml
+++ b/tests/integration/j-376/pom.xml
@@ -86,8 +86,6 @@
         <dependency>
             <groupId>org.glassfish.grizzly</groupId>
             <artifactId>grizzly-http-server</artifactId>
-            <version>2.3.16</version>
-            <scope>compile</scope>
         </dependency>
 
         <dependency>
diff --git a/tests/integration/jersey-4003/src/test/java/org/glassfish/jersey/tests/integration/jersey4003/LostResponseTest.java b/tests/integration/jersey-4003/src/test/java/org/glassfish/jersey/tests/integration/jersey4003/LostResponseTest.java
index 710ff81..059e450 100644
--- a/tests/integration/jersey-4003/src/test/java/org/glassfish/jersey/tests/integration/jersey4003/LostResponseTest.java
+++ b/tests/integration/jersey-4003/src/test/java/org/glassfish/jersey/tests/integration/jersey4003/LostResponseTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 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
@@ -59,7 +59,7 @@
         HttpUrlConnectorProvider.ConnectionFactory connectionFactory =
                 Mockito.mock(HttpUrlConnectorProvider.ConnectionFactory.class);
         HttpURLConnection connection = Mockito.mock(HttpURLConnection.class);
-        Mockito.when(connectionFactory.getConnection(Mockito.any(URL.class))).thenReturn(connection);
+        Mockito.when(connectionFactory.getConnection(Mockito.any(URL.class), Mockito.any())).thenReturn(connection);
 
         OutputStream outputStream = Mockito.mock(OutputStream.class);
         Mockito.when(connection.getOutputStream()).thenReturn(outputStream);
diff --git a/tests/integration/jersey-5087/pom.xml b/tests/integration/jersey-5087/pom.xml
new file mode 100644
index 0000000..efbfe3c
--- /dev/null
+++ b/tests/integration/jersey-5087/pom.xml
@@ -0,0 +1,333 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 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
+    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
+
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>project</artifactId>
+        <groupId>org.glassfish.jersey.tests.integration</groupId>
+        <version>3.1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>jersey-5087</artifactId>
+    <packaging>war</packaging>
+    <name>jersey-tests-integration-jersey-5087</name>
+
+    <description>dependencyConvergence rule check</description>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.glassfish.jersey</groupId>
+                <artifactId>jersey-bom</artifactId>
+                <version>${project.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-server</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.bundles</groupId>
+            <artifactId>jaxrs-ri</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.connectors</groupId>
+            <artifactId>jersey-apache-connector</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.connectors</groupId>
+            <artifactId>jersey-apache5-connector</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.connectors</groupId>
+            <artifactId>jersey-helidon-connector</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.connectors</groupId>
+            <artifactId>jersey-grizzly-connector</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.connectors</groupId>
+            <artifactId>jersey-jetty-connector</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.connectors</groupId>
+            <artifactId>jersey-jdk-connector</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.connectors</groupId>
+            <artifactId>jersey-netty-connector</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.containers</groupId>
+            <artifactId>jersey-container-jetty-http</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.containers</groupId>
+            <artifactId>jersey-container-grizzly2-http</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.containers</groupId>
+            <artifactId>jersey-container-grizzly2-servlet</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.containers</groupId>
+            <artifactId>jersey-container-jetty-servlet</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.containers</groupId>
+            <artifactId>jersey-container-jdk-http</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.containers</groupId>
+            <artifactId>jersey-container-netty-http</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.containers</groupId>
+            <artifactId>jersey-container-servlet</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.containers</groupId>
+            <artifactId>jersey-container-servlet-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.containers</groupId>
+            <artifactId>jersey-container-simple-http</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.containers.glassfish</groupId>
+            <artifactId>jersey-gf-ejb</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext</groupId>
+            <artifactId>jersey-bean-validation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext</groupId>
+            <artifactId>jersey-entity-filtering</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext</groupId>
+            <artifactId>jersey-metainf-services</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext.microprofile</groupId>
+            <artifactId>jersey-mp-config</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext</groupId>
+            <artifactId>jersey-mvc</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext</groupId>
+            <artifactId>jersey-mvc-bean-validation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext</groupId>
+            <artifactId>jersey-mvc-freemarker</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext</groupId>
+            <artifactId>jersey-mvc-jsp</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext</groupId>
+            <artifactId>jersey-mvc-mustache</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext</groupId>
+            <artifactId>jersey-proxy-client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext</groupId>
+            <artifactId>jersey-spring6</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext</groupId>
+            <artifactId>jersey-declarative-linking</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext</groupId>
+            <artifactId>jersey-wadl-doclet</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext.cdi</groupId>
+            <artifactId>jersey-weld2-se</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext.cdi</groupId>
+            <artifactId>jersey-cdi1x</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext.cdi</groupId>
+            <artifactId>jersey-cdi1x-transaction</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext.cdi</groupId>
+            <artifactId>jersey-cdi1x-validation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext.cdi</groupId>
+            <artifactId>jersey-cdi1x-servlet</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext.cdi</groupId>
+            <artifactId>jersey-cdi1x-ban-custom-hk2-binding</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext.cdi</groupId>
+            <artifactId>jersey-cdi-rs-inject</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext.rx</groupId>
+            <artifactId>jersey-rx-client-guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext.rx</groupId>
+            <artifactId>jersey-rx-client-rxjava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext.rx</groupId>
+            <artifactId>jersey-rx-client-rxjava2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext.microprofile</groupId>
+            <artifactId>jersey-mp-rest-client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.media</groupId>
+            <artifactId>jersey-media-jaxb</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.media</groupId>
+            <artifactId>jersey-media-json-jackson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.media</groupId>
+            <artifactId>jersey-media-json-jettison</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.media</groupId>
+            <artifactId>jersey-media-json-processing</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.media</groupId>
+            <artifactId>jersey-media-json-binding</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.media</groupId>
+            <artifactId>jersey-media-kryo</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.media</groupId>
+            <artifactId>jersey-media-moxy</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.media</groupId>
+            <artifactId>jersey-media-multipart</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.media</groupId>
+            <artifactId>jersey-media-sse</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.security</groupId>
+            <artifactId>oauth1-client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.security</groupId>
+            <artifactId>oauth1-server</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.security</groupId>
+            <artifactId>oauth1-signature</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.security</groupId>
+            <artifactId>oauth2-client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.inject</groupId>
+            <artifactId>jersey-hk2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.inject</groupId>
+            <artifactId>jersey-cdi2-se</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework</groupId>
+            <artifactId>jersey-test-framework-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+            <artifactId>jersey-test-framework-provider-bundle</artifactId>
+            <type>pom</type>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+            <artifactId>jersey-test-framework-provider-external</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+            <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+            <artifactId>jersey-test-framework-provider-inmemory</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+            <artifactId>jersey-test-framework-provider-jdk-http</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+            <artifactId>jersey-test-framework-provider-simple</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+            <artifactId>jersey-test-framework-provider-jetty</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework</groupId>
+            <artifactId>jersey-test-framework-util</artifactId>
+        </dependency>
+
+    </dependencies>
+
+    <properties>
+        <maven.test.skip>true</maven.test.skip> <!-- do not run any tests here, it's useless,
+        dependencies clash is being tested even before compilation. -->
+    </properties>
+</project>
\ No newline at end of file
diff --git a/tests/integration/jersey-5087/src/main/java/org/glassfish/jersey/tests/integration/jersey5087/Jersey5087.java b/tests/integration/jersey-5087/src/main/java/org/glassfish/jersey/tests/integration/jersey5087/Jersey5087.java
new file mode 100644
index 0000000..05f4d67
--- /dev/null
+++ b/tests/integration/jersey-5087/src/main/java/org/glassfish/jersey/tests/integration/jersey5087/Jersey5087.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 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
+ * 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.integration.jersey5087;
+
+import org.glassfish.jersey.server.ResourceConfig;
+
+public class Jersey5087 extends ResourceConfig {
+
+    public Jersey5087() {
+        register(Resource5087.class);
+    }
+}
diff --git a/tests/integration/jersey-5087/src/main/java/org/glassfish/jersey/tests/integration/jersey5087/Resource5087.java b/tests/integration/jersey-5087/src/main/java/org/glassfish/jersey/tests/integration/jersey5087/Resource5087.java
new file mode 100644
index 0000000..ce32dc3
--- /dev/null
+++ b/tests/integration/jersey-5087/src/main/java/org/glassfish/jersey/tests/integration/jersey5087/Resource5087.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 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
+ * 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.integration.jersey5087;
+
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+
+@Path("/")
+public class Resource5087 {
+
+    @GET
+    public String getResource() {
+        return "OK";
+    }
+
+}
diff --git a/tests/integration/jersey-5087/src/test/java/org/glassfish/jersey/tests/integration/jersey5087/Jersey5087Test.java b/tests/integration/jersey-5087/src/test/java/org/glassfish/jersey/tests/integration/jersey5087/Jersey5087Test.java
new file mode 100644
index 0000000..8c1b3be
--- /dev/null
+++ b/tests/integration/jersey-5087/src/test/java/org/glassfish/jersey/tests/integration/jersey5087/Jersey5087Test.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 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
+ * 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.integration.jersey5087;
+
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.server.ServerProperties;
+import org.glassfish.jersey.test.DeploymentContext;
+import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.ServletDeploymentContext;
+import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
+import org.glassfish.jersey.test.spi.TestContainerFactory;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.EnumSet;
+
+public class Jersey5087Test extends JerseyTest {
+
+    @Override
+    protected ResourceConfig configure() {
+        return new Jersey5087();
+    }
+
+    @Override
+    protected TestContainerFactory getTestContainerFactory() {
+        return new GrizzlyWebTestContainerFactory();
+    }
+
+    @Override
+    protected DeploymentContext configureDeployment() {
+        return ServletDeploymentContext.newInstance(Jersey5087.class);
+    }
+
+    @Test
+    public void testDependenciesClash() {
+        final String response = target().request().get(String.class);
+        Assert.assertEquals("OK", response);
+    }
+}
diff --git a/tests/integration/pom.xml b/tests/integration/pom.xml
index dc72108..c0289fb 100644
--- a/tests/integration/pom.xml
+++ b/tests/integration/pom.xml
@@ -92,6 +92,7 @@
         <module>jersey-4697</module>
         <module>jersey-4722</module>
         <module>jersey-4949</module>
+        <module>jersey-5087</module>
         <module>microprofile</module>
         <module>property-check</module>
         <module>reactive-streams</module>
@@ -189,6 +190,15 @@
                 </pluginManagement>
             </build>
         </profile>
+        <profile>
+            <id>spring6-jdk17</id>
+            <activation>
+                <jdk>[17,)</jdk>
+            </activation>
+            <modules>
+                <module>spring6</module>
+            </modules>
+        </profile>
     </profiles>
 
     <build>
diff --git a/tests/osgi/functional/pom.xml b/tests/osgi/functional/pom.xml
index eb31c6b..10fc862 100644
--- a/tests/osgi/functional/pom.xml
+++ b/tests/osgi/functional/pom.xml
@@ -34,6 +34,10 @@
         Functional Jersey OSGi tests
     </description>
 
+    <properties>
+        <enforcer.skip>true</enforcer.skip>
+    </properties>
+
     <build>
         <plugins>
             <plugin>