merge of the actual master into 3.x branch

diff --git a/NOTICE.md b/NOTICE.md
index 6f2a9ea..ca03fd1 100644
--- a/NOTICE.md
+++ b/NOTICE.md
@@ -47,7 +47,7 @@
 * Copyright: 2009, Red Hat, Inc. and/or its affiliates, and individual contributors

 * by the @authors tag.

 

-Hibernate Validator CDI, 7.0.0.Final

+Hibernate Validator CDI, 7.0.5.Final

 * License: Apache License, 2.0

 * Project: https://beanvalidation.org/

 * Repackaged in org.glassfish.jersey.server.validation.internal.hibernate

@@ -65,7 +65,7 @@
 * License: Apache License, 2.0

 * Copyright (C) 2009 The JSR-330 Expert Group

 

-Javassist Version 3.25.0-GA

+Javassist Version 3.29.0-GA

 * License: Apache License, 2.0

 * Project: http://www.javassist.org/

 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.

@@ -95,7 +95,7 @@
 * Project: http://www.kineticjs.com, https://github.com/ericdrowell/KineticJS

 * Copyright: Eric Rowell

 

-org.objectweb.asm Version 9.3

+org.objectweb.asm Version 9.4

 * License: Modified BSD (https://asm.ow2.io/license.html)

 * Copyright (c) 2000-2011 INRIA, France Telecom. All rights reserved.

 

diff --git a/bundles/apidocs/pom.xml b/bundles/apidocs/pom.xml
index 2658a92..073f826 100644
--- a/bundles/apidocs/pom.xml
+++ b/bundles/apidocs/pom.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
 
-    Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2012, 2023 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
@@ -63,12 +63,12 @@
             <groupId>org.glassfish.jersey.connectors</groupId>
             <artifactId>jersey-apache-connector</artifactId>
             <version>${project.version}</version>
-            <exclusions>
+            <!--<exclusions>
                 <exclusion>
                     <groupId>commons-codec</groupId>
                     <artifactId>commons-codec</artifactId>
                 </exclusion>
-            </exclusions>
+            </exclusions>-->
         </dependency>
         <dependency>
             <groupId>org.glassfish.jersey.connectors</groupId>
diff --git a/connectors/apache-connector/pom.xml b/connectors/apache-connector/pom.xml
index 269b753..b36502a 100644
--- a/connectors/apache-connector/pom.xml
+++ b/connectors/apache-connector/pom.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <!--
 
-    Copyright (c) 2011, 2022 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2011, 2023 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
@@ -40,18 +40,6 @@
         <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 fdfbccf..264c453 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -24,6 +24,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.net.Socket;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.LinkedList;
@@ -46,6 +47,7 @@
 
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
 import javax.net.ssl.SSLSocketFactory;
 
 import org.glassfish.jersey.client.ClientProperties;
@@ -53,6 +55,7 @@
 import org.glassfish.jersey.client.ClientResponse;
 import org.glassfish.jersey.client.RequestEntityProcessing;
 import org.glassfish.jersey.client.innate.ClientProxy;
+import org.glassfish.jersey.client.innate.http.SSLParamConfigurator;
 import org.glassfish.jersey.client.spi.AsyncConnectorCallback;
 import org.glassfish.jersey.client.spi.Connector;
 import org.glassfish.jersey.internal.util.PropertiesHelper;
@@ -103,6 +106,7 @@
 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 import org.apache.http.impl.io.ChunkedOutputStream;
 import org.apache.http.io.SessionOutputBuffer;
+import org.apache.http.protocol.HttpContext;
 import org.apache.http.util.TextUtils;
 import org.apache.http.util.VersionInfo;
 
@@ -180,6 +184,7 @@
 class ApacheConnector implements Connector {
 
     private static final Logger LOGGER = Logger.getLogger(ApacheConnector.class.getName());
+    private static final String JERSEY_REQUEST_ATTR_NAME = "JerseyRequestAttribute";
     private static final VersionInfo vi;
     private static final String release;
 
@@ -255,10 +260,16 @@
             }
         }
 
+        final boolean useSystemProperties =
+                PropertiesHelper.isProperty(config.getProperties(), ApacheClientProperties.USE_SYSTEM_PROPERTIES);
+
         final SSLContext sslContext = client.getSslContext();
         final HttpClientBuilder clientBuilder = HttpClientBuilder.create();
 
-        clientBuilder.setConnectionManager(getConnectionManager(client, config, sslContext));
+        if (useSystemProperties) {
+            clientBuilder.useSystemProperties();
+        }
+        clientBuilder.setConnectionManager(getConnectionManager(client, config, sslContext, useSystemProperties));
         clientBuilder.setConnectionManagerShared(
                 PropertiesHelper.getValue(config.getProperties(), ApacheClientProperties.CONNECTION_MANAGER_SHARED, false, null));
         clientBuilder.setSSLContext(sslContext);
@@ -337,7 +348,8 @@
 
     private HttpClientConnectionManager getConnectionManager(final Client client,
                                                              final Configuration config,
-                                                             final SSLContext sslContext) {
+                                                             final SSLContext sslContext,
+                                                             final boolean useSystemProperties) {
         final Object cmObject = config.getProperties().get(ApacheClientProperties.CONNECTION_MANAGER);
 
         // Connection manager from configuration.
@@ -355,9 +367,6 @@
             }
         }
 
-        final boolean useSystemProperties =
-            PropertiesHelper.isProperty(config.getProperties(), ApacheClientProperties.USE_SYSTEM_PROPERTIES);
-
         // Create custom connection manager.
         return createConnectionManager(
                 client,
@@ -381,15 +390,15 @@
 
         final LayeredConnectionSocketFactory sslSocketFactory;
         if (sslContext != null) {
-            sslSocketFactory = new SSLConnectionSocketFactory(
+            sslSocketFactory = new SniSSLConnectionSocketFactory(
                     sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifier);
         } else {
             if (useSystemProperties) {
-                sslSocketFactory = new SSLConnectionSocketFactory(
+                sslSocketFactory = new SniSSLConnectionSocketFactory(
                         (SSLSocketFactory) SSLSocketFactory.getDefault(),
                         supportedProtocols, supportedCipherSuites, hostnameVerifier);
             } else {
-                sslSocketFactory = new SSLConnectionSocketFactory(
+                sslSocketFactory = new SniSSLConnectionSocketFactory(
                         SSLContexts.createDefault(),
                         hostnameVerifier);
             }
@@ -450,14 +459,16 @@
     public ClientResponse apply(final ClientRequest clientRequest) throws ProcessingException {
         final HttpUriRequest request = getUriHttpRequest(clientRequest);
         final Map<String, String> clientHeadersSnapshot = writeOutBoundHeaders(clientRequest, request);
+        final HttpHost httpHost = getHost(request);
 
         try {
             final CloseableHttpResponse response;
             final HttpClientContext context = HttpClientContext.create();
+
             if (preemptiveBasicAuth) {
                 final AuthCache authCache = new BasicAuthCache();
                 final BasicScheme basicScheme = new BasicScheme();
-                authCache.put(getHost(request), basicScheme);
+                authCache.put(httpHost, basicScheme);
                 context.setAuthCache(authCache);
             }
 
@@ -468,7 +479,8 @@
                 context.setCredentialsProvider(credentialsProvider);
             }
 
-            response = client.execute(getHost(request), request, context);
+            context.setAttribute(JERSEY_REQUEST_ATTR_NAME, clientRequest);
+            response = client.execute(httpHost, request, context);
             HeaderUtils.checkHeaderChanges(clientHeadersSnapshot, clientRequest.getHeaders(),
                     this.getClass().getName(), clientRequest.getConfiguration());
 
@@ -821,4 +833,56 @@
             return super.createOutputStream(len, outbuffer);
         }
     }
+
+    private static final class SniSSLConnectionSocketFactory extends SSLConnectionSocketFactory {
+
+        private final ThreadLocal<HttpContext> httpContexts = new ThreadLocal<>();
+
+        public SniSSLConnectionSocketFactory(final SSLContext sslContext,
+                                             final String[] supportedProtocols,
+                                             final String[] supportedCipherSuites,
+                                             final HostnameVerifier hostnameVerifier) {
+            super(sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifier);
+        }
+
+        public SniSSLConnectionSocketFactory(final javax.net.ssl.SSLSocketFactory socketFactory,
+                                             final String[] supportedProtocols,
+                                             final String[] supportedCipherSuites,
+                                             final HostnameVerifier hostnameVerifier) {
+            super(socketFactory, supportedProtocols, supportedCipherSuites, hostnameVerifier);
+        }
+
+        public SniSSLConnectionSocketFactory(
+                final SSLContext sslContext, final HostnameVerifier hostnameVerifier) {
+            super(sslContext, hostnameVerifier);
+        }
+
+        @Override
+        public Socket createLayeredSocket(
+                final Socket socket,
+                final String target,
+                final int port,
+                final HttpContext context) throws IOException {
+            httpContexts.set(context);
+            try {
+                return super.createLayeredSocket(socket, target, port, context);
+            } finally {
+                httpContexts.remove();
+            }
+        }
+
+        @Override
+        protected void prepareSocket(SSLSocket socket) throws IOException {
+            HttpContext context = httpContexts.get();
+
+            if (context != null) {
+                Object objectRequest = context.getAttribute(JERSEY_REQUEST_ATTR_NAME);
+                if (objectRequest != null) {
+                    ClientRequest clientRequest = (ClientRequest) objectRequest;
+                    SSLParamConfigurator sniConfig = SSLParamConfigurator.builder().request(clientRequest).build();
+                    sniConfig.setSNIServerName(socket);
+                }
+            }
+        }
+    }
 }
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 9e4e9ac..f7c30a9 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2023 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -24,6 +24,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.net.Socket;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
@@ -46,8 +47,10 @@
 
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
 import javax.net.ssl.SSLSocketFactory;
 
+import org.apache.hc.client5.http.AuthenticationStrategy;
 import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
 import org.apache.hc.client5.http.HttpRequestRetryStrategy;
 import org.apache.hc.client5.http.auth.AuthCache;
@@ -65,6 +68,7 @@
 import org.apache.hc.client5.http.impl.auth.BasicAuthCache;
 import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
 import org.apache.hc.client5.http.impl.auth.BasicScheme;
+import org.apache.hc.client5.http.impl.classic.BasicHttpClientResponseHandler;
 import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
 import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
 import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
@@ -86,6 +90,7 @@
 import org.apache.hc.core5.http.impl.DefaultContentLengthStrategy;
 import org.apache.hc.core5.http.io.entity.AbstractHttpEntity;
 import org.apache.hc.core5.http.io.entity.BufferedHttpEntity;
+import org.apache.hc.core5.http.protocol.HttpContext;
 import org.apache.hc.core5.ssl.SSLContexts;
 import org.apache.hc.core5.util.TextUtils;
 import org.apache.hc.core5.util.Timeout;
@@ -95,6 +100,7 @@
 import org.glassfish.jersey.client.ClientResponse;
 import org.glassfish.jersey.client.RequestEntityProcessing;
 import org.glassfish.jersey.client.innate.ClientProxy;
+import org.glassfish.jersey.client.innate.http.SSLParamConfigurator;
 import org.glassfish.jersey.client.spi.AsyncConnectorCallback;
 import org.glassfish.jersey.client.spi.Connector;
 import org.glassfish.jersey.internal.util.PropertiesHelper;
@@ -176,6 +182,7 @@
 class Apache5Connector implements Connector {
 
     private static final Logger LOGGER = Logger.getLogger(Apache5Connector.class.getName());
+    private static final String JERSEY_REQUEST_ATTR_NAME = "JerseyRequestAttribute";
     private static final VersionInfo vi;
     private static final String release;
 
@@ -251,10 +258,17 @@
             }
         }
 
+        final boolean useSystemProperties =
+                PropertiesHelper.isProperty(config.getProperties(), Apache5ClientProperties.USE_SYSTEM_PROPERTIES);
+
         final SSLContext sslContext = client.getSslContext();
         final HttpClientBuilder clientBuilder = HttpClientBuilder.create();
 
-        clientBuilder.setConnectionManager(getConnectionManager(client, config, sslContext));
+        if (useSystemProperties) {
+            clientBuilder.useSystemProperties();
+        }
+
+        clientBuilder.setConnectionManager(getConnectionManager(client, config, sslContext, useSystemProperties));
         clientBuilder.setConnectionManagerShared(
                 PropertiesHelper.getValue(
                         config.getProperties(),
@@ -341,7 +355,8 @@
 
     private HttpClientConnectionManager getConnectionManager(final Client client,
                                                              final Configuration config,
-                                                             final SSLContext sslContext) {
+                                                             final SSLContext sslContext,
+                                                             final boolean useSystemProperties) {
         final Object cmObject = config.getProperties().get(Apache5ClientProperties.CONNECTION_MANAGER);
 
         // Connection manager from configuration.
@@ -359,9 +374,6 @@
             }
         }
 
-        final boolean useSystemProperties =
-            PropertiesHelper.isProperty(config.getProperties(), Apache5ClientProperties.USE_SYSTEM_PROPERTIES);
-
         // Create custom connection manager.
         return createConnectionManager(
                 client,
@@ -385,15 +397,15 @@
 
         final LayeredConnectionSocketFactory sslSocketFactory;
         if (sslContext != null) {
-            sslSocketFactory = new SSLConnectionSocketFactory(
+            sslSocketFactory = new SniSSLConnectionSocketFactory(
                     sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifier);
         } else {
             if (useSystemProperties) {
-                sslSocketFactory = new SSLConnectionSocketFactory(
+                sslSocketFactory = new SniSSLConnectionSocketFactory(
                         (SSLSocketFactory) SSLSocketFactory.getDefault(),
                         supportedProtocols, supportedCipherSuites, hostnameVerifier);
             } else {
-                sslSocketFactory = new SSLConnectionSocketFactory(
+                sslSocketFactory = new SniSSLConnectionSocketFactory(
                         SSLContexts.createDefault(),
                         hostnameVerifier);
             }
@@ -458,12 +470,7 @@
         try {
             final CloseableHttpResponse response;
             final HttpClientContext context = HttpClientContext.create();
-            if (preemptiveBasicAuth) {
-                final AuthCache authCache = new BasicAuthCache();
-                final BasicScheme basicScheme = new BasicScheme();
-                authCache.put(getHost(request), basicScheme);
-                context.setAuthCache(authCache);
-            }
+            final HttpHost httpHost = getHost(request);
 
             // If a request-specific CredentialsProvider exists, use it instead of the default one
             CredentialsProvider credentialsProvider =
@@ -472,7 +479,18 @@
                 context.setCredentialsProvider(credentialsProvider);
             }
 
-            response = client.execute(getHost(request), request, context);
+            if (preemptiveBasicAuth) {
+                final AuthCache authCache = new BasicAuthCache();
+                final BasicScheme basicScheme = new BasicScheme();
+                final AuthScope authScope = new AuthScope(httpHost);
+                basicScheme.initPreemptive(credentialsProvider.getCredentials(authScope, context));
+                context.resetAuthExchange(httpHost, basicScheme);
+                authCache.put(httpHost, basicScheme); // must be after initPreemptive
+                context.setAuthCache(authCache);
+            }
+
+            context.setAttribute(JERSEY_REQUEST_ATTR_NAME, clientRequest);
+            response = client.execute(httpHost, request, context);
             HeaderUtils.checkHeaderChanges(clientHeadersSnapshot, clientRequest.getHeaders(),
                     this.getClass().getName(), clientRequest.getConfiguration());
 
@@ -798,4 +816,77 @@
             );
         }
     }
+
+    private static final class SniSSLConnectionSocketFactory extends SSLConnectionSocketFactory {
+
+        private final ThreadLocal<HttpContext> httpContexts = new ThreadLocal<>();
+
+        public SniSSLConnectionSocketFactory(final SSLContext sslContext,
+                                             final String[] supportedProtocols,
+                                             final String[] supportedCipherSuites,
+                                             final HostnameVerifier hostnameVerifier) {
+            super(sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifier);
+        }
+
+        public SniSSLConnectionSocketFactory(final javax.net.ssl.SSLSocketFactory socketFactory,
+                                             final String[] supportedProtocols,
+                                             final String[] supportedCipherSuites,
+                                             final HostnameVerifier hostnameVerifier) {
+            super(socketFactory, supportedProtocols, supportedCipherSuites, hostnameVerifier);
+        }
+
+        public SniSSLConnectionSocketFactory(
+                final SSLContext sslContext, final HostnameVerifier hostnameVerifier) {
+            super(sslContext, hostnameVerifier);
+        }
+
+        /* Pre 5.2 */
+        @Override
+        public Socket createLayeredSocket(
+                final Socket socket,
+                final String target,
+                final int port,
+                final HttpContext context) throws IOException {
+            httpContexts.set(context);
+            try {
+                return super.createLayeredSocket(socket, target, port, context);
+            } finally {
+                httpContexts.remove();
+            }
+        }
+
+        /* Post 5.2 */
+        public Socket createLayeredSocket(
+                final Socket socket,
+                final String target,
+                final int port,
+                final Object attachment,
+                final HttpContext context) throws IOException {
+            httpContexts.set(context);
+            try {
+                return super.createLayeredSocket(socket, target, port, attachment, context);
+            } finally {
+                httpContexts.remove();
+            }
+        }
+
+        @Override
+        protected void prepareSocket(SSLSocket socket) throws IOException {
+            HttpContext context =  httpContexts.get();
+
+            if (context != null) {
+                Object objectRequest = context.getAttribute(JERSEY_REQUEST_ATTR_NAME);
+                if (objectRequest != null) {
+                    ClientRequest clientRequest = (ClientRequest) objectRequest;
+                    SSLParamConfigurator sniConfig = SSLParamConfigurator.builder().request(clientRequest).build();
+                    sniConfig.setSNIServerName(socket);
+
+                    final int socketTimeout = ((ClientRequest) objectRequest).resolveProperty(ClientProperties.READ_TIMEOUT, -1);
+                    if (socketTimeout >= 0) {
+                        socket.setSoTimeout(socketTimeout);
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/ConnectorConfiguration.java b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/ConnectorConfiguration.java
index 39fb0ab..422d919 100644
--- a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/ConnectorConfiguration.java
+++ b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/ConnectorConfiguration.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023 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,6 +19,7 @@
 import java.net.CookiePolicy;
 import java.net.URI;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -30,6 +31,7 @@
 
 import org.glassfish.jersey.SslConfigurator;
 import org.glassfish.jersey.client.ClientProperties;
+import org.glassfish.jersey.client.innate.http.SSLParamConfigurator;
 import org.glassfish.jersey.jdk.connector.JdkConnectorProperties;
 
 /**
@@ -57,6 +59,7 @@
     private final int responseTimeout;
     private final int connectTimeout;
     private final ProxyConfiguration proxyConfiguration;
+    private final AtomicReference<SSLParamConfigurator> sniConfigs = new AtomicReference<>(null);
 
     ConnectorConfiguration(Client client, Configuration config) {
         final Map<String, Object> properties = config.getProperties();
@@ -170,6 +173,14 @@
         return proxyConfiguration;
     }
 
+    void setSniConfig(SSLParamConfigurator sniConfig) {
+        this.sniConfigs.compareAndSet(null, sniConfig);
+    }
+
+    SSLParamConfigurator getSniConfig() {
+        return sniConfigs.get();
+    }
+
     @Override
     public String toString() {
         return "ConnectorConfiguration{"
diff --git a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpConnection.java b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpConnection.java
index 2330dd4..d9ea76e 100644
--- a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpConnection.java
+++ b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpConnection.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023 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
@@ -199,7 +199,8 @@
 
             }
 
-            socket = new SslFilter(transportFilter, sslContext, uri.getHost(), configuration.getHostnameVerifier());
+            socket = new SslFilter(transportFilter, sslContext, uri.getHost(),
+                            configuration.getHostnameVerifier(), configuration.getSniConfig());
         } else {
             socket = new TransportFilter(INPUT_BUFFER_SIZE, configuration.getThreadPoolConfig(),
                     configuration.getContainerIdleTimeout());
diff --git a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpConnectionPool.java b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpConnectionPool.java
index 28c7500..b20f00c 100644
--- a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpConnectionPool.java
+++ b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/HttpConnectionPool.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023 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,7 +16,11 @@
 
 package org.glassfish.jersey.jdk.connector.internal;
 
+import org.glassfish.jersey.client.innate.http.SSLParamConfigurator;
+
 import java.net.CookieManager;
+import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executors;
@@ -45,10 +49,16 @@
     }
 
     void send(HttpRequest httpRequest, CompletionHandler<HttpResponse> completionHandler) {
+        final Map<String, List<Object>> headers = new HashMap<>();
+        httpRequest.getHeaders().forEach((k, v) -> headers.put(k, (List) v));
+        final SSLParamConfigurator sniConfig = SSLParamConfigurator.builder().uri(httpRequest.getUri()).headers(headers).build();
+        connectorConfiguration.setSniConfig(sniConfig);
+
         final DestinationConnectionPool.DestinationKey destinationKey = new DestinationConnectionPool.DestinationKey(
-                httpRequest.getUri());
+                sniConfig.getSNIUri());
         DestinationConnectionPool destinationConnectionPool = destinationPools.get(destinationKey);
 
+
         if (destinationConnectionPool == null) {
             synchronized (this) {
                 // check again while holding the lock
diff --git a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/SslFilter.java b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/SslFilter.java
index 85f4541..979a9ce 100644
--- a/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/SslFilter.java
+++ b/connectors/jdk-connector/src/main/java/org/glassfish/jersey/jdk/connector/internal/SslFilter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023 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,6 +16,8 @@
 
 package org.glassfish.jersey.jdk.connector.internal;
 
+import org.glassfish.jersey.client.innate.http.SSLParamConfigurator;
+
 import java.nio.ByteBuffer;
 import java.nio.Buffer;
 import java.util.LinkedList;
@@ -26,7 +28,6 @@
 import javax.net.ssl.SSLEngine;
 import javax.net.ssl.SSLEngineResult;
 import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLParameters;
 
 
 /**
@@ -87,7 +88,8 @@
     SslFilter(Filter<ByteBuffer, ByteBuffer, ?, ?> downstreamFilter,
               SSLContext sslContext,
               String serverHost,
-              HostnameVerifier customHostnameVerifier) {
+              HostnameVerifier customHostnameVerifier,
+              SSLParamConfigurator sniConfig) {
         super(downstreamFilter);
         this.serverHost = serverHost;
         sslEngine = sslContext.createSSLEngine(serverHost, -1);
@@ -100,11 +102,11 @@
          * when {@link SslEngineConfigurator} supports Java 7.
          */
         if (customHostnameVerifier == null) {
-            SSLParameters sslParameters = sslEngine.getSSLParameters();
-            sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
-            sslEngine.setSSLParameters(sslParameters);
+            sniConfig.setEndpointIdentificationAlgorithm(sslEngine);
         }
 
+        sniConfig.setSNIServerName(sslEngine);
+
         applicationInputBuffer = ByteBuffer.allocate(sslEngine.getSession().getApplicationBufferSize());
         networkOutputBuffer = ByteBuffer.allocate(sslEngine.getSession().getPacketBufferSize());
     }
diff --git a/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/SslFilterTest.java b/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/SslFilterTest.java
index 5d205ce..ef13997 100644
--- a/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/SslFilterTest.java
+++ b/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/SslFilterTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023 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,10 +23,12 @@
 import java.net.InetSocketAddress;
 import java.net.ServerSocket;
 import java.net.SocketException;
+import java.net.URI;
 import java.nio.ByteBuffer;
 import java.security.KeyManagementException;
 import java.security.NoSuchAlgorithmException;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
@@ -41,7 +43,9 @@
 import javax.net.ssl.SSLServerSocketFactory;
 import javax.net.ssl.SSLSession;
 import javax.net.ssl.SSLSocket;
+
 import org.glassfish.jersey.SslConfigurator;
+import org.glassfish.jersey.client.innate.http.SSLParamConfigurator;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ConditionEvaluationResult;
 import org.junit.jupiter.api.extension.ExecutionCondition;
@@ -391,7 +395,10 @@
                 .keyStorePassword("asdfgh");
 
         TransportFilter transportFilter = new TransportFilter(17_000, ThreadPoolConfig.defaultConfig(), 100_000);
-        final SslFilter sslFilter = new SslFilter(transportFilter, sslConfig.createSSLContext(), host, customHostnameVerifier);
+        final SSLParamConfigurator sslParamConfigurator = SSLParamConfigurator.builder()
+                .uri(URI.create("Https://" + host)).headers(Collections.emptyMap()).build();
+        final SslFilter sslFilter = new SslFilter(
+                transportFilter, sslConfig.createSSLContext(), host, customHostnameVerifier, sslParamConfigurator);
 
         // exceptions errors that occur before SSL handshake has finished are thrown from this method
         final AtomicReference<Throwable> exception = new AtomicReference<>();
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 5d52e76..5a776b6 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2023 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
@@ -83,6 +83,7 @@
 import org.glassfish.jersey.client.ClientRequest;
 import org.glassfish.jersey.client.ClientResponse;
 import org.glassfish.jersey.client.innate.ClientProxy;
+import org.glassfish.jersey.client.innate.http.SSLParamConfigurator;
 import org.glassfish.jersey.client.spi.AsyncConnectorCallback;
 import org.glassfish.jersey.client.spi.Connector;
 import org.glassfish.jersey.message.internal.OutboundMessageContext;
@@ -278,17 +279,20 @@
                                  (String[]) null, /* enable default protocols */
                                  false /* true if the first write request shouldn't be encrypted */
                          );
-                         int port = requestUri.getPort();
-                         SslHandler sslHandler = jdkSslContext.newHandler(ch.alloc(), requestUri.getHost(),
-                                                                          port <= 0 ? 443 : port, executorService);
+
+                         final int port = requestUri.getPort();
+                         final SSLParamConfigurator sslConfig = SSLParamConfigurator.builder()
+                                 .request(jerseyRequest).setSNIAlways(true).build();
+                         final SslHandler sslHandler = jdkSslContext.newHandler(
+                                 ch.alloc(), sslConfig.getSNIHostName(), port <= 0 ? 443 : port, executorService
+                         );
                          if (ClientProperties.getValue(config.getProperties(),
                                                        NettyClientProperties.ENABLE_SSL_HOSTNAME_VERIFICATION, true)) {
-                            SSLEngine sslEngine = sslHandler.engine();
-                            SSLParameters sslParameters = sslEngine.getSSLParameters();
-                            sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
-                            sslEngine.setSSLParameters(sslParameters);
+                             sslConfig.setEndpointIdentificationAlgorithm(sslHandler.engine());
                          }
 
+                         sslConfig.setSNIServerName(sslHandler.engine());
+
                          p.addLast(sslHandler);
                      }
 
@@ -374,7 +378,9 @@
             setHeaders(jerseyRequest, nettyRequest.headers());
 
             // host header - http 1.1
-            nettyRequest.headers().add(HttpHeaderNames.HOST, jerseyRequest.getUri().getHost());
+            if (!nettyRequest.headers().contains(HttpHeaderNames.HOST)) {
+                nettyRequest.headers().add(HttpHeaderNames.HOST, jerseyRequest.getUri().getHost());
+            }
 
             if (jerseyRequest.hasEntity()) {
                 // guard against prematurely closed channel
diff --git a/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/FollowRedirectsTest.java b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/FollowRedirectsTest.java
index f675270..3a1cf69 100644
--- a/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/FollowRedirectsTest.java
+++ b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/FollowRedirectsTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2023 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
@@ -20,6 +20,7 @@
 import static org.junit.jupiter.api.Assertions.fail;
 
 import java.net.URI;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.logging.Logger;
 
 import jakarta.ws.rs.GET;
@@ -37,12 +38,20 @@
 import org.glassfish.jersey.netty.connector.internal.RedirectException;
 import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.test.JerseyTest;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 public class FollowRedirectsTest extends JerseyTest {
 
     private static final Logger LOGGER = Logger.getLogger(FollowRedirectsTest.class.getName());
-    private static final String TEST_URL = "http://localhost:9998/test";
+    private static final String TEST_URL = "http://localhost:%d/test";
+    private static final AtomicReference<String> TEST_URL_REF = new AtomicReference<>();
+
+    @BeforeEach
+    public void before() {
+        final String url = String.format(TEST_URL, getPort());
+        TEST_URL_REF.set(url);
+    }
 
     @Path("/test")
     public static class RedirectResource {
@@ -54,19 +63,19 @@
         @GET
         @Path("redirect")
         public Response redirect() {
-            return Response.seeOther(URI.create(TEST_URL)).build();
+            return Response.seeOther(URI.create(TEST_URL_REF.get())).build();
         }
 
         @GET
         @Path("loop")
         public Response loop() {
-            return Response.seeOther(URI.create(TEST_URL + "/loop")).build();
+            return Response.seeOther(URI.create(TEST_URL_REF.get() + "/loop")).build();
         }
 
         @GET
         @Path("redirect2")
         public Response redirect2() {
-            return Response.seeOther(URI.create(TEST_URL + "/redirect")).build();
+            return Response.seeOther(URI.create(TEST_URL_REF.get() + "/redirect")).build();
         }
     }
 
diff --git a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java
index 4f769f2..3886ea9 100644
--- a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java
+++ b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2023 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
@@ -21,6 +21,7 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import jakarta.ws.rs.RuntimeType;
 import jakarta.ws.rs.core.UriBuilder;
 
 import com.sun.net.httpserver.HttpServer;
@@ -37,7 +38,7 @@
 public abstract class AbstractJdkHttpServerTester {
 
     public static final String CONTEXT = "";
-    private final int DEFAULT_PORT = 9998;
+    private final int DEFAULT_PORT = 0; // rather JDK server choose than 9998
 
     private static final Logger LOGGER = Logger.getLogger(AbstractJdkHttpServerTester.class.getName());
 
@@ -47,6 +48,9 @@
      * @return The HTTP port of the URI
      */
     protected final int getPort() {
+        if (server != null) {
+            return server.getAddress().getPort();
+        }
         final String value =
                 AccessController.doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port"));
         if (value != null) {
@@ -68,10 +72,20 @@
         return DEFAULT_PORT;
     }
 
+    private final int getPort(RuntimeType runtimeType) {
+        switch (runtimeType) {
+            case SERVER:
+                return getPort();
+            case CLIENT:
+                return server.getAddress().getPort();
+            default:
+                throw new IllegalStateException("Unexpected runtime type");
+        }
+    }
     private volatile HttpServer server;
 
     public UriBuilder getUri() {
-        return UriBuilder.fromUri("http://localhost").port(getPort()).path(CONTEXT);
+        return UriBuilder.fromUri("http://localhost").port(getPort(RuntimeType.CLIENT)).path(CONTEXT);
     }
 
     public void startServer(Class... resources) {
@@ -79,18 +93,18 @@
         config.register(LoggingFeature.class);
         final URI baseUri = getBaseUri();
         server = JdkHttpServerFactory.createHttpServer(baseUri, config);
-        LOGGER.log(Level.INFO, "jdk-http server started on base uri: " + baseUri);
+        LOGGER.log(Level.INFO, "jdk-http server started on base uri: " + server.getAddress());
     }
 
     public void startServer(ResourceConfig config) {
         final URI baseUri = getBaseUri();
         config.register(LoggingFeature.class);
         server = JdkHttpServerFactory.createHttpServer(baseUri, config);
-        LOGGER.log(Level.INFO, "jdk-http server started on base uri: " + baseUri);
+        LOGGER.log(Level.INFO, "jdk-http server started on base uri: " + server.getAddress());
     }
 
     public URI getBaseUri() {
-        return UriBuilder.fromUri("http://localhost/").port(getPort()).build();
+        return UriBuilder.fromUri("http://localhost/").port(getPort(RuntimeType.SERVER)).build();
     }
 
     public void stopServer() {
diff --git a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java
index 0ad2944..472d5ed 100644
--- a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java
+++ b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023 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
@@ -116,7 +116,7 @@
             // access the https server with not configured client
             final Client client = ClientBuilder.newBuilder().newClient();
             try {
-                client.target(httpsUri).path("testHttps").request().get(String.class);
+                client.target(updatePort(httpsUri)).path("testHttps").request().get(String.class);
             } catch (final ProcessingException e) {
                 throw e.getCause();
             }
@@ -136,8 +136,8 @@
             server.start();
 
             final Client client = ClientBuilder.newBuilder().newClient();
-           try {
-                client.target(httpsUri).path("testHttps").request().get(String.class);
+            try {
+                client.target(updatePort(httpsUri)).path("testHttps").request().get(String.class);
             } catch (final ProcessingException e) {
                 throw e.getCause();
             }
@@ -173,7 +173,7 @@
 
         final SSLContext clientSslContext = getClientSslContext();
         final Client client = ClientBuilder.newBuilder().sslContext(clientSslContext).build();
-        final String response = client.target(httpsUri).path("testHttps").request().get(String.class);
+        final String response = client.target(updatePort(httpsUri)).path("testHttps").request().get(String.class);
 
         assertEquals("test", response);
     }
@@ -216,6 +216,11 @@
         return sslConfigServer.createSSLContext();
     }
 
+
+    private URI updatePort(URI uri) {
+        return UriBuilder.fromUri(httpsUri).port(server.getAddress().getPort()).build();
+    }
+
     @AfterEach
     public void tearDown() {
         if (server != null) {
diff --git a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java
index 1d7cac2..3a953e1 100644
--- a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java
+++ b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 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
@@ -21,6 +21,7 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import jakarta.ws.rs.RuntimeType;
 import jakarta.ws.rs.core.UriBuilder;
 
 import org.glassfish.jersey.logging.LoggingFeature;
@@ -42,7 +43,7 @@
     private static final Logger LOGGER = Logger.getLogger(AbstractJettyServerTester.class.getName());
 
     public static final String CONTEXT = "";
-    private static final int DEFAULT_PORT = 9998;
+    private static final int DEFAULT_PORT = 0; // rather Jetty choose than 9998
 
     /**
      * Get the port to be used for test application deployments.
@@ -71,10 +72,21 @@
         return DEFAULT_PORT;
     }
 
+    private final int getPort(RuntimeType runtimeType) {
+        switch (runtimeType) {
+            case SERVER:
+                return getPort();
+            case CLIENT:
+                return server.getURI().getPort();
+            default:
+                throw new IllegalStateException("Unexpected runtime type");
+        }
+    }
+
     private volatile Server server;
 
     public UriBuilder getUri() {
-        return UriBuilder.fromUri("http://localhost").port(getPort()).path(CONTEXT);
+        return UriBuilder.fromUri("http://localhost").port(getPort(RuntimeType.CLIENT)).path(CONTEXT);
     }
 
     public void startServer(Class... resources) {
@@ -82,17 +94,17 @@
         config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY));
         final URI baseUri = getBaseUri();
         server = JettyHttpContainerFactory.createServer(baseUri, config);
-        LOGGER.log(Level.INFO, "Jetty-http server started on base uri: " + baseUri);
+        LOGGER.log(Level.INFO, "Jetty-http server started on base uri: " + server.getURI());
     }
 
     public void startServer(ResourceConfig config) {
         final URI baseUri = getBaseUri();
         server = JettyHttpContainerFactory.createServer(baseUri, config);
-        LOGGER.log(Level.INFO, "Jetty-http server started on base uri: " + baseUri);
+        LOGGER.log(Level.INFO, "Jetty-http server started on base uri: " + server.getURI());
     }
 
     public URI getBaseUri() {
-        return UriBuilder.fromUri("http://localhost/").port(getPort()).build();
+        return UriBuilder.fromUri("http://localhost/").port(getPort(RuntimeType.SERVER)).build();
     }
 
     public void stopServer() {
diff --git a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java
index d36c54f..3543e50 100644
--- a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java
+++ b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 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
@@ -21,6 +21,7 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import jakarta.ws.rs.RuntimeType;
 import jakarta.ws.rs.core.UriBuilder;
 
 import org.glassfish.jersey.internal.util.PropertiesHelper;
@@ -39,7 +40,7 @@
 public abstract class AbstractSimpleServerTester {
 
     public static final String CONTEXT = "";
-    private final int DEFAULT_PORT = 9998;
+    private final int DEFAULT_PORT = 0; // rather SimpleFramework server choose than 9998
 
     private static final Logger LOGGER = Logger.getLogger(AbstractSimpleServerTester.class.getName());
 
@@ -72,10 +73,20 @@
         return DEFAULT_PORT;
     }
 
+    private final int getPort(RuntimeType runtimeType) {
+        switch (runtimeType) {
+            case SERVER:
+                return getPort();
+            case CLIENT:
+                return server.getPort();
+            default:
+                throw new IllegalStateException("Unexpected runtime type");
+        }
+    }
     private volatile SimpleServer server;
 
     public UriBuilder getUri() {
-        return UriBuilder.fromUri("http://localhost").port(getPort()).path(CONTEXT);
+        return UriBuilder.fromUri("http://localhost").port(getPort(RuntimeType.CLIENT)).path(CONTEXT);
     }
 
     public void startServer(Class... resources) {
@@ -83,21 +94,21 @@
         config.register(LoggingFeature.class);
         final URI baseUri = getBaseUri();
         server = SimpleContainerFactory.create(baseUri, config);
-        LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri);
+        LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri.getHost() + ":" + server.getPort());
     }
 
     public void startServerNoLoggingFilter(Class... resources) {
         ResourceConfig config = new ResourceConfig(resources);
         final URI baseUri = getBaseUri();
         server = SimpleContainerFactory.create(baseUri, config);
-        LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri);
+        LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri.getHost() + ":" + server.getPort());
     }
 
     public void startServer(ResourceConfig config) {
         final URI baseUri = getBaseUri();
         config.register(LoggingFeature.class);
         server = SimpleContainerFactory.create(baseUri, config);
-        LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri);
+        LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri.getHost() + ":" + server.getPort());
     }
 
     public void startServer(ResourceConfig config, int count, int select) {
@@ -108,7 +119,7 @@
     }
 
     public URI getBaseUri() {
-        return UriBuilder.fromUri("http://localhost/").port(getPort()).build();
+        return UriBuilder.fromUri("http://localhost/").port(getPort(RuntimeType.SERVER)).build();
     }
 
     public void setDebug(boolean enable) {
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/ChunkedInputReader.java b/core-client/src/main/java/org/glassfish/jersey/client/ChunkedInputReader.java
index 72374cc..8ecbfaa 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/ChunkedInputReader.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/ChunkedInputReader.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 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
@@ -43,10 +43,15 @@
 @ConstrainedTo(RuntimeType.CLIENT)
 class ChunkedInputReader implements MessageBodyReader<ChunkedInput> {
 
+    private final Provider<MessageBodyWorkers> messageBodyWorkers;
+    private final Provider<PropertiesDelegate> propertiesDelegateProvider;
+
     @Inject
-    private Provider<MessageBodyWorkers> messageBodyWorkers;
-    @Inject
-    private Provider<PropertiesDelegate> propertiesDelegateProvider;
+    public ChunkedInputReader(Provider<MessageBodyWorkers> messageBodyWorkers,
+                              Provider<PropertiesDelegate> propertiesDelegateProvider) {
+        this.messageBodyWorkers = messageBodyWorkers;
+        this.propertiesDelegateProvider = propertiesDelegateProvider;
+    }
 
     @Override
     public boolean isReadable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/ClientConfig.java b/core-client/src/main/java/org/glassfish/jersey/client/ClientConfig.java
index 43737f1..4dca460 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/ClientConfig.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/ClientConfig.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2018 Payara Foundation and/or its affiliates.
  *
  * This program and the accompanying materials are made available under the
@@ -35,6 +35,7 @@
 import org.glassfish.jersey.CommonProperties;
 import org.glassfish.jersey.ExtendedConfig;
 import org.glassfish.jersey.client.internal.LocalizationMessages;
+import org.glassfish.jersey.client.innate.inject.NonInjectionManager;
 import org.glassfish.jersey.client.internal.inject.ParameterUpdaterConfigurator;
 import org.glassfish.jersey.client.spi.Connector;
 import org.glassfish.jersey.client.spi.ConnectorProvider;
@@ -410,7 +411,7 @@
             final State runtimeCfgState = this.copy();
             runtimeCfgState.markAsShared();
 
-            InjectionManager injectionManager = Injections.createInjectionManager();
+            final InjectionManager injectionManager = findInjectionManager();
             injectionManager.register(new ClientBinder(runtimeCfgState.getProperties()));
 
             final ClientBootstrapBag bootstrapBag = new ClientBootstrapBag();
@@ -471,6 +472,14 @@
             return crt;
         }
 
+        private final InjectionManager findInjectionManager() {
+            try {
+                return Injections.createInjectionManager(RuntimeType.CLIENT);
+            } catch (IllegalStateException ise) {
+                return new NonInjectionManager(true);
+            }
+        }
+
         @Override
         public boolean equals(final Object o) {
             if (this == o) {
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/filter/EncodingFilter.java b/core-client/src/main/java/org/glassfish/jersey/client/filter/EncodingFilter.java
index 7b99abd..8d773a6 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/filter/EncodingFilter.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/filter/EncodingFilter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 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
@@ -49,10 +49,15 @@
  * @author Martin Matula
  */
 public final class EncodingFilter implements ClientRequestFilter {
-    @Inject
-    private InjectionManager injectionManager;
+
+    private final InjectionManager injectionManager;
     private volatile List<Object> supportedEncodings = null;
 
+    @Inject
+    public EncodingFilter(InjectionManager injectionManager) {
+        this.injectionManager = injectionManager;
+    }
+
     @Override
     public void filter(ClientRequestContext request) throws IOException {
         if (getSupportedEncodings().isEmpty()) {
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SSLParamConfigurator.java b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SSLParamConfigurator.java
new file mode 100644
index 0000000..33ef0b6
--- /dev/null
+++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SSLParamConfigurator.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2023 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.http;
+
+import org.glassfish.jersey.client.ClientRequest;
+
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSocket;
+import jakarta.ws.rs.core.UriBuilder;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.UnknownHostException;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * A unified routines to configure {@link SSLParameters}.
+ * To be reused in connectors.
+ */
+public final class SSLParamConfigurator {
+    private final URI uri;
+    private final Map<String, List<Object>> httpHeaders;
+    private final Optional<SniConfigurator> sniConfigurator;
+
+    /**
+     * Builder of the {@link SSLParamConfigurator} instance.
+     */
+    public static final class Builder {
+        private ClientRequest clientRequest;
+        private URI uri;
+        private Map<String, List<Object>> httpHeaders;
+        private boolean setAlways = false;
+
+        /**
+         * Sets the {@link ClientRequest} instance.
+         * @param clientRequest the {@link ClientRequest}
+         * @return the builder instance
+         */
+        public Builder request(ClientRequest clientRequest) {
+            this.clientRequest = clientRequest;
+            this.httpHeaders = null;
+            this.uri = null;
+            return this;
+        }
+
+        /**
+         * Sets the HTTP request {@link URI} instance.
+         * @param uri The request uri
+         * @return the builder instance
+         */
+        public Builder uri(URI uri) {
+            this.clientRequest = null;
+            this.uri = uri;
+            return this;
+        }
+
+        /**
+         * Sets the HTTP request headers
+         * @param httpHeaders the http request headers
+         * @return the builder instance
+         */
+        public Builder headers(Map<String, List<Object>> httpHeaders) {
+            this.clientRequest = null;
+            this.httpHeaders = httpHeaders;
+            return this;
+        }
+
+        /**
+         * Sets SNI only when {@link jakarta.ws.rs.core.HttpHeaders#HOST} differs from the request host name if set to
+         * {@code false}. Default is {@code false}.
+         * @param setAlways set SNI always (default)
+         * @return the builder instance
+         */
+        public Builder setSNIAlways(boolean setAlways) {
+            this.setAlways = setAlways;
+            return this;
+        }
+
+        /**
+         * Builds the {@link SSLParamConfigurator} instance.
+         * @return the configured {@link SSLParamConfigurator} instance.
+         */
+        public SSLParamConfigurator build() {
+            return new SSLParamConfigurator(this);
+        }
+    }
+
+    private SSLParamConfigurator(SSLParamConfigurator.Builder builder) {
+        this.uri = builder.clientRequest != null ? builder.clientRequest.getUri() : builder.uri;
+        this.httpHeaders = builder.clientRequest != null ? builder.clientRequest.getHeaders() : builder.httpHeaders;
+        sniConfigurator = SniConfigurator.createWhenHostHeader(uri, httpHeaders, builder.setAlways);
+    }
+
+    /**
+     * Create a new instance of TlsSupport class
+     **/
+    public static SSLParamConfigurator.Builder builder() {
+        return new SSLParamConfigurator.Builder();
+    }
+
+    /**
+     * Get the host name either set by the request URI or by
+     * {@link jakarta.ws.rs.core.HttpHeaders#HOST} header if it differs from HTTP request host name.
+     * @return the hostName the {@link SSLEngine} is to use.
+     */
+    public String getSNIHostName() {
+        return sniConfigurator.isPresent() ? sniConfigurator.get().getHostName() : uri.getHost();
+    }
+
+    /**
+     * Replaces hostname within the {@link ClientRequest} uri with a resolved IP address. Should the hostname be not known,
+     * the original request URI is returned. The purpose of this method is to replace the host with the IP so that
+     * {code HttpUrlConnection} does not replace user defined {@link javax.net.ssl.SNIHostName} with the host from the request
+     * uri.
+     * @return the request uri with ip address of the resolved host.
+     */
+    public URI toIPRequestUri() {
+        String host = uri.getHost();
+        try {
+            InetAddress ip = InetAddress.getByName(host);
+            return UriBuilder.fromUri(uri).host(ip.getHostAddress()).build();
+        } catch (UnknownHostException e) {
+            return uri;
+        }
+    }
+
+    /**
+     * Return true iff SNI is to be set, i.e.
+     * {@link jakarta.ws.rs.core.HttpHeaders#HOST} header if it differs from HTTP request host name.
+     * @return Return {@code true} when {@link javax.net.ssl.SNIHostName} is to be set.
+     */
+    public boolean isSNIRequired() {
+        return sniConfigurator.isPresent();
+    }
+
+    /**
+     * Get the request URI or altered by {@link jakarta.ws.rs.core.HttpHeaders#HOST} header.
+     * @return The possibly altered request URI.
+     * @see #getSNIHostName()
+     */
+    public URI getSNIUri() {
+        return sniConfigurator.isPresent() ? UriBuilder.fromUri(uri).host(getSNIHostName()).build() : uri;
+    }
+
+    /**
+     * Set {@link javax.net.ssl.SNIServerName} for the {@link SSLParameters} when SNI should be used
+     * (i.e. {@link jakarta.ws.rs.core.HttpHeaders#HOST} differs from HTTP request host name)
+     * @param sslEngine the {@link SSLEngine} the {@link SSLParameters} are set for.
+     */
+    public void setSNIServerName(SSLEngine sslEngine) {
+        sniConfigurator.ifPresent(sni -> sni.setServerNames(sslEngine));
+    }
+
+
+    /**
+     * Set {@link javax.net.ssl.SNIServerName} for the {@link SSLParameters} when SNI should be used
+     * (i.e. {@link jakarta.ws.rs.core.HttpHeaders#HOST} differs from HTTP request host name)
+     * @param sslSocket the {@link SSLSocket} the {@link SSLParameters} are set for.
+     */
+    public void setSNIServerName(SSLSocket sslSocket) {
+        sniConfigurator.ifPresent(sni -> sni.setServerNames(sslSocket));
+    }
+
+    /**
+     * Set setEndpointIdentificationAlgorithm to HTTPS. This is to prevent man-in-the-middle attacks.
+     * @param sslEngine the {@link SSLEngine} the algorithm is set for.
+     * @see SSLParameters#setEndpointIdentificationAlgorithm(String)
+     */
+    public void setEndpointIdentificationAlgorithm(SSLEngine sslEngine) {
+        SSLParameters sslParameters = sslEngine.getSSLParameters();
+        sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
+        sslEngine.setSSLParameters(sslParameters);
+    }
+}
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SniConfigurator.java b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SniConfigurator.java
new file mode 100644
index 0000000..39a339d
--- /dev/null
+++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SniConfigurator.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2023 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.http;
+
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SNIServerName;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSocket;
+import jakarta.ws.rs.core.HttpHeaders;
+import java.net.URI;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * A unified routines to set {@link SNIHostName} for the {@link javax.net.ssl.SSLContext}.
+ * To be reused in connectors.
+ */
+final class SniConfigurator {
+    private final String hostName;
+    private SniConfigurator(String hostName) {
+        this.hostName = hostName;
+    }
+
+    /**
+     * Get the hostName from the {@link HttpHeaders#HOST} header.
+     * @return
+     */
+    String getHostName() {
+        return hostName;
+    }
+
+    /**
+     * Create ClientSNI when {@link HttpHeaders#HOST} is set different from the request URI host (or {@code whenDiffer}.is false).
+     * @param hostUri the Uri of the HTTP request
+     * @param headers the HttpHeaders
+     * @param whenDiffer create {@SniConfigurator only when different from the request URI host}
+     * @return ClientSNI or empty when {@link HttpHeaders#HOST}
+     */
+    static Optional<SniConfigurator> createWhenHostHeader(URI hostUri, Map<String, List<Object>> headers, boolean whenDiffer) {
+        List<Object> hostHeaders = headers.get(HttpHeaders.HOST);
+        if (hostHeaders == null || hostHeaders.get(0) == null) {
+            return Optional.empty();
+        }
+
+        final String hostHeader = hostHeaders.get(0).toString();
+        final String trimmedHeader;
+        if (hostHeader != null) {
+            int index = hostHeader.indexOf(':'); // RFC 7230  Host = uri-host [ ":" port ] ;
+            final String trimmedHeader0 = index != -1 ? hostHeader.substring(0, index).trim() : hostHeader.trim();
+            trimmedHeader = trimmedHeader0.isEmpty() ? hostHeader : trimmedHeader0;
+        } else {
+            return Optional.empty();
+        }
+
+        final String hostUriString = hostUri.getHost();
+        if (!whenDiffer && hostUriString.equals(trimmedHeader)) {
+            return Optional.empty();
+        }
+
+        return Optional.of(new SniConfigurator(trimmedHeader));
+    }
+
+    /**
+     * Set {@link SNIServerName} for the given {@link SSLEngine} SSLParameters.
+     * @param sslEngine
+     */
+    void setServerNames(SSLEngine sslEngine) {
+        SSLParameters sslParameters = sslEngine.getSSLParameters();
+        updateSSLParameters(sslParameters);
+        sslEngine.setSSLParameters(sslParameters);
+    }
+
+    /**
+     * Set {@link SNIServerName} for the given {@link SSLSocket} SSLParameters.
+     * @param sslSocket
+     */
+    void setServerNames(SSLSocket sslSocket) {
+        SSLParameters sslParameters = sslSocket.getSSLParameters();
+        updateSSLParameters(sslParameters);
+        sslSocket.setSSLParameters(sslParameters);
+    }
+
+    private SSLParameters updateSSLParameters(SSLParameters sslParameters) {
+        SNIHostName serverName = new SNIHostName(hostName);
+        List<SNIServerName> serverNames = new LinkedList<>();
+        serverNames.add(serverName);
+
+        sslParameters.setServerNames(serverNames);
+
+        return sslParameters;
+    }
+
+}
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/innate/http/package-info.java b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/package-info.java
new file mode 100644
index 0000000..bbedce0
--- /dev/null
+++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2023 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 http related classes/interfaces.
+ * Shall not be used outside of Jersey. The module shall not be exported to outside of Jersey.
+ */
+package org.glassfish.jersey.client.innate.http;
\ No newline at end of file
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/innate/inject/NonInjectionManager.java b/core-client/src/main/java/org/glassfish/jersey/client/innate/inject/NonInjectionManager.java
new file mode 100644
index 0000000..7062bab
--- /dev/null
+++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/inject/NonInjectionManager.java
@@ -0,0 +1,1029 @@
+/*
+ * Copyright (c) 2023 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.inject;
+
+import org.glassfish.jersey.client.internal.LocalizationMessages;
+import org.glassfish.jersey.internal.inject.Binder;
+import org.glassfish.jersey.internal.inject.Binding;
+import org.glassfish.jersey.internal.inject.ClassBinding;
+import org.glassfish.jersey.internal.inject.DisposableSupplier;
+import org.glassfish.jersey.internal.inject.ForeignDescriptor;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.inject.InstanceBinding;
+import org.glassfish.jersey.internal.inject.PerThread;
+import org.glassfish.jersey.internal.inject.ServiceHolder;
+import org.glassfish.jersey.internal.inject.ServiceHolderImpl;
+import org.glassfish.jersey.internal.inject.SupplierClassBinding;
+import org.glassfish.jersey.internal.inject.SupplierInstanceBinding;
+import org.glassfish.jersey.internal.util.collection.LazyValue;
+import org.glassfish.jersey.internal.util.collection.Value;
+import org.glassfish.jersey.internal.util.collection.Values;
+import org.glassfish.jersey.process.internal.RequestScope;
+import org.glassfish.jersey.process.internal.RequestScoped;
+
+import jakarta.annotation.PostConstruct;
+import jakarta.annotation.PreDestroy;
+import jakarta.inject.Inject;
+import jakarta.inject.Provider;
+import jakarta.inject.Singleton;
+import jakarta.ws.rs.ConstrainedTo;
+import jakarta.ws.rs.RuntimeType;
+import jakarta.ws.rs.core.MultivaluedHashMap;
+import jakarta.ws.rs.core.MultivaluedMap;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.function.Supplier;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+@ConstrainedTo(RuntimeType.CLIENT)
+public final class NonInjectionManager implements InjectionManager {
+    private static final Logger logger = Logger.getLogger(NonInjectionManager.class.getName());
+
+    private final MultivaluedMap<Class<?>, InstanceBinding<?>> instanceBindings = new MultivaluedHashMap<>();
+    private final MultivaluedMap<Class<?>, ClassBinding<?>> contractBindings = new MultivaluedHashMap<>();
+    private final MultivaluedMap<Class<?>, SupplierInstanceBinding<?>> supplierInstanceBindings = new MultivaluedHashMap<>();
+    private final MultivaluedMap<Class<?>, SupplierClassBinding<?>> supplierClassBindings = new MultivaluedHashMap<>();
+    private final MultivaluedMap<Type, InstanceBinding<?>> instanceTypeBindings = new MultivaluedHashMap<>();
+    private final MultivaluedMap<Type, ClassBinding<?>> contractTypeBindings = new MultivaluedHashMap<>();
+    private final MultivaluedMap<Type, SupplierInstanceBinding<?>> supplierTypeInstanceBindings = new MultivaluedHashMap<>();
+    private final MultivaluedMap<Type, SupplierClassBinding<?>> supplierTypeClassBindings = new MultivaluedHashMap<>();
+
+    private final MultivaluedMap<DisposableSupplier, Object> disposableSupplierObjects = new MultivaluedHashMap<>();
+
+    private final Instances instances = new Instances();
+    private final Types types = new Types();
+
+    private volatile boolean isRequestScope = false;
+    private volatile boolean shutdown = false;
+
+    /**
+     * A class that holds singleton instances and thread-scope instances. Provides thread safe access to singletons
+     * and thread-scope instances. The instances are created for Type (ParametrizedType) and for a Class.
+     * @param <TYPE> the type for which the instance is created, either Class, or ParametrizedType (for instance
+     * Provider&lt;SomeClass&gt;).
+     */
+    private class TypedInstances<TYPE> {
+        private final MultivaluedMap<TYPE, InstanceContext<?>> singletonInstances = new MultivaluedHashMap<>();
+        private final ThreadLocal<MultivaluedMap<TYPE, InstanceContext<?>>> threadInstances = new ThreadLocal<>();
+        private final List<Object> threadPredestroyables = Collections.synchronizedList(new LinkedList<>());
+
+        private <T> List<InstanceContext<?>> _getSingletons(TYPE clazz) {
+            List<InstanceContext<?>> si;
+            synchronized (singletonInstances) {
+                si = singletonInstances.get(clazz);
+            }
+            return si;
+        }
+
+        @SuppressWarnings("unchecked")
+        <T> T _addSingleton(TYPE clazz, T instance, Binding<?, ?> binding, Annotation[] qualifiers) {
+            synchronized (singletonInstances) {
+                // check existing singleton with a qualifier already created by another thread io a meantime
+                List<InstanceContext<?>> values = singletonInstances.get(clazz);
+                if (values != null) {
+                    List<InstanceContext<?>> qualified
+                            = values.stream()
+                                    .filter(ctx -> ctx.hasQualifiers(qualifiers))
+                                    .collect(Collectors.toList());
+                    if (!qualified.isEmpty()) {
+                        return (T) qualified.get(0).instance;
+                    }
+                }
+                singletonInstances.add(clazz, new InstanceContext<>(instance, binding, qualifiers));
+                threadPredestroyables.add(instance);
+                return instance;
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        <T> T addSingleton(TYPE clazz, T t, Binding<?, ?> binding, Annotation[] instanceQualifiers) {
+            T t2  = _addSingleton(clazz, t, binding, instanceQualifiers);
+            if (t2 == t) {
+                for (Type contract : binding.getContracts()) {
+                    if (!clazz.equals(contract) && isClass(contract)) {
+                        _addSingleton((TYPE) contract, t, binding, instanceQualifiers);
+                    }
+                }
+            }
+            return t2;
+        }
+
+        private List<InstanceContext<?>> _getThreadInstances(TYPE clazz) {
+            MultivaluedMap<TYPE, InstanceContext<?>> ti = threadInstances.get();
+            List<InstanceContext<?>> list = ti == null ? null : new LinkedList<>();
+            if (ti != null) {
+                return ti.get(clazz);
+            }
+            return list;
+        }
+
+        private <T> void _addThreadInstance(TYPE clazz, T instance, Binding<T, ?> binding, Annotation[] qualifiers) {
+            MultivaluedMap<TYPE, InstanceContext<?>> map = threadInstances.get();
+            if (map == null) {
+                map = new MultivaluedHashMap<>();
+                threadInstances.set(map);
+            }
+            map.add(clazz, new InstanceContext<>(instance, binding, qualifiers));
+            threadPredestroyables.add(instance);
+        }
+
+        <T> void addThreadInstance(TYPE clazz, T t, Binding<T, ?> binding, Annotation[] instanceQualifiers) {
+            _addThreadInstance(clazz, t, binding, instanceQualifiers);
+            for (Type contract : binding.getContracts()) {
+                if (!clazz.equals(contract) && isClass(contract)) {
+                    _addThreadInstance((TYPE) contract, t, binding, instanceQualifiers);
+                }
+            }
+        }
+
+        private <T> List<T> getInstances(TYPE clazz, Annotation[] annotations) {
+            List<InstanceContext<?>> i = _getContexts(clazz);
+            return InstanceContext.toInstances(i, annotations);
+        }
+
+        <T> List<InstanceContext<?>> getContexts(TYPE clazz, Annotation[] annotations) {
+            List<InstanceContext<?>> i = _getContexts(clazz);
+            return InstanceContext.filterInstances(i, annotations);
+        }
+
+        private <T> List<InstanceContext<?>> _getContexts(TYPE clazz) {
+            List<InstanceContext<?>> si = _getSingletons(clazz);
+            List<InstanceContext<?>> ti = _getThreadInstances(clazz);
+            if (si == null && ti != null) {
+                si = ti;
+            } else if (ti != null) {
+                si.addAll(ti);
+            }
+            return si;
+        }
+
+        <T> T getInstance(TYPE clazz, Annotation[] annotations) {
+            List<T> i = getInstances(clazz, annotations);
+            if (i != null) {
+                checkUnique(i);
+                return i.get(0);
+            }
+            return null;
+        }
+
+        void dispose() {
+            singletonInstances.forEach((clazz, instances) -> instances.forEach(instance -> preDestroy(instance.getInstance())));
+            threadPredestroyables.forEach(NonInjectionManager.this::preDestroy);
+        }
+    }
+
+    private class Instances extends TypedInstances<Class<?>> {
+    }
+
+    private class Types extends TypedInstances<Type> {
+    }
+
+    public NonInjectionManager() {
+    }
+
+    public NonInjectionManager(boolean warning) {
+        if (warning) {
+            logger.warning(LocalizationMessages.NONINJECT_FALLBACK());
+        } else {
+            logger.log(Level.FINER, LocalizationMessages.NONINJECT_FALLBACK());
+        }
+    }
+
+    @Override
+    public void completeRegistration() {
+        instances._addSingleton(InjectionManager.class, this, new InjectionManagerBinding(), null);
+    }
+
+    @Override
+    public void shutdown() {
+        shutdown = true;
+
+        disposableSupplierObjects.forEach((supplier, objects) -> objects.forEach(supplier::dispose));
+        disposableSupplierObjects.clear();
+
+        instances.dispose();
+        types.dispose();
+    }
+
+    @Override
+    public boolean isShutdown() {
+        return shutdown;
+    }
+
+    private void checkShutdown() {
+        if (shutdown) {
+            throw new IllegalStateException(LocalizationMessages.NONINJECT_SHUTDOWN());
+        }
+    }
+
+    @Override
+    public void register(Binding binding) {
+        checkShutdown();
+        if (InstanceBinding.class.isInstance(binding)) {
+            InstanceBinding instanceBinding = (InstanceBinding) binding;
+            Class<?> mainType = binding.getImplementationType();
+            if (!instanceBindings.containsKey(mainType)) { // the class could be registered twice, for reader & for writer
+                instanceBindings.add(mainType, (InstanceBinding) binding);
+            }
+            for (Type type : (Iterable<Type>) instanceBinding.getContracts()) {
+                if (isClass(type)) {
+                    if (!mainType.equals(type)) {
+                        instanceBindings.add((Class<?>) type, instanceBinding);
+                    }
+                } else {
+                    instanceTypeBindings.add(type, instanceBinding);
+                }
+            }
+        } else if (ClassBinding.class.isInstance(binding)) {
+            ClassBinding<?> contractBinding = (ClassBinding<?>) binding;
+            Class<?> mainType = binding.getImplementationType();
+            if (!contractBindings.containsKey(mainType)) { // the class could be registered twice, for reader & for writer
+                contractBindings.add(mainType, contractBinding);
+            }
+            for (Type type : contractBinding.getContracts()) {
+                if (isClass(type)) {
+                    if (!mainType.equals(type)) {
+                        contractBindings.add((Class<?>) type, contractBinding);
+                    }
+                } else {
+                    contractTypeBindings.add(type, contractBinding);
+                }
+            }
+        } else if (SupplierInstanceBinding.class.isInstance(binding)) {
+            SupplierInstanceBinding<?> supplierBinding = (SupplierInstanceBinding<?>) binding;
+            for (Type type : supplierBinding.getContracts()) {
+                if (isClass(type)) {
+                    supplierInstanceBindings.add((Class<?>) type, supplierBinding);
+                } else {
+                    supplierTypeInstanceBindings.add(type, supplierBinding);
+                }
+            }
+        } else if (SupplierClassBinding.class.isInstance(binding)) {
+            SupplierClassBinding<?> supplierBinding = (SupplierClassBinding<?>) binding;
+            for (Type type : supplierBinding.getContracts()) {
+                if (isClass(type)) {
+                    supplierClassBindings.add((Class<?>) type, supplierBinding);
+                } else {
+                    supplierTypeClassBindings.add(type, supplierBinding);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void register(Iterable<Binding> descriptors) {
+        checkShutdown();
+        for (Binding binding : descriptors) {
+            register(binding);
+        }
+    }
+
+    @Override
+    public void register(Binder binder) {
+        checkShutdown();
+        binder.getBindings().stream().iterator().forEachRemaining(this::register);
+    }
+
+    @Override
+    public void register(Object provider) throws IllegalArgumentException {
+        throw new UnsupportedOperationException("Register " + provider);
+    }
+
+    @Override
+    public boolean isRegistrable(Class<?> clazz) {
+        return false; // for external creators
+    }
+
+    @Override
+    public <T> List<ServiceHolder<T>> getAllServiceHolders(Class<T> contractOrImpl, Annotation... qualifiers) {
+        checkShutdown();
+
+        ClassBindings<T> classBindings = classBindings(contractOrImpl, qualifiers);
+        return classBindings.getAllServiceHolders(qualifiers);
+    }
+
+    @Override
+    public <T> T getInstance(Class<T> contractOrImpl, Annotation... qualifiers) {
+        checkShutdown();
+
+        ClassBindings<T> classBindings = classBindings(contractOrImpl, qualifiers);
+        classBindings.matchQualifiers(qualifiers);
+        return classBindings.getInstance();
+    }
+
+    @Override
+    public <T> T getInstance(Class<T> contractOrImpl, String classAnalyzer) {
+        throw new UnsupportedOperationException("getInstance(Class, String)");
+    }
+
+    @Override
+    public <T> T getInstance(Class<T> contractOrImpl) {
+        checkShutdown();
+
+        T instance = instances.getInstance(contractOrImpl, null);
+        if (instance != null) {
+            return instance;
+        }
+        return create(contractOrImpl);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T> T getInstance(Type contractOrImpl) {
+        checkShutdown();
+
+        if (ParameterizedType.class.isInstance(contractOrImpl)) {
+            T instance = types.getInstance(contractOrImpl, null);
+            if (instance != null) {
+                return instance;
+            }
+
+            TypeBindings<T> typeBindings = typeBindings(contractOrImpl);
+            return typeBindings.getInstance();
+        } else if (isClass(contractOrImpl)) {
+            return getInstance((Class<? extends T>) contractOrImpl);
+        }
+        throw new IllegalStateException(LocalizationMessages.NONINJECT_UNSATISFIED(contractOrImpl));
+    }
+
+    private static boolean isClass(Type type) {
+        return Class.class.isAssignableFrom(type.getClass());
+    }
+
+    @Override
+    public Object getInstance(ForeignDescriptor foreignDescriptor) {
+        throw new UnsupportedOperationException("getInstance(ForeignDescriptor foreignDescriptor) ");
+    }
+
+    @Override
+    public ForeignDescriptor createForeignDescriptor(Binding binding) {
+        throw new UnsupportedOperationException("createForeignDescriptor(Binding binding) ");
+    }
+
+    @Override
+    public <T> List<T> getAllInstances(Type contractOrImpl) {
+        checkShutdown();
+
+        if (!isClass(contractOrImpl)) {
+            TypeBindings<T> typeBindings = typeBindings(contractOrImpl);
+            return typeBindings.allInstances();
+        }
+
+        @SuppressWarnings("unchecked")
+        ClassBindings<T> classBindings = classBindings((Class<T>) contractOrImpl);
+        return classBindings.allInstances();
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> T create(Class<T> createMe) {
+        checkShutdown();
+
+        if (InjectionManager.class.equals(createMe)) {
+            return (T) this;
+        }
+        if (RequestScope.class.equals(createMe)) {
+            if (!isRequestScope) {
+                isRequestScope = true;
+                return (T) new NonInjectionRequestScope();
+            } else {
+                throw new IllegalStateException(LocalizationMessages.NONINJECT_REQUESTSCOPE_CREATED());
+            }
+        }
+
+        ClassBindings<T> classBindings = classBindings(createMe);
+        return classBindings.create();
+    }
+
+    private <T> T justCreate(Class<T> createMe) {
+        T result = null;
+        try {
+            Constructor<T> mostArgConstructor = findConstructor(createMe);
+            if (mostArgConstructor != null) {
+                int argCount = mostArgConstructor.getParameterCount();
+                if (argCount == 0) {
+                    ensureAccessible(mostArgConstructor);
+                    result = mostArgConstructor.newInstance();
+                } else if (argCount > 0) {
+                    Object[] args = getArguments(mostArgConstructor, argCount);
+                    if (args != null) {
+                        ensureAccessible(mostArgConstructor);
+                        result = mostArgConstructor.newInstance(args);
+                    }
+                }
+            }
+            if (result == null) {
+                throw new IllegalStateException(LocalizationMessages.NONINJECT_NO_CONSTRUCTOR(createMe.getName()));
+            }
+        } catch (Exception e) {
+            throw new IllegalStateException(e);
+        }
+
+        inject(result);
+        return result;
+    }
+
+    private static <T> Constructor<T> findConstructor(Class<T> forClass) {
+        Constructor<T>[] constructors = (Constructor<T>[]) forClass.getDeclaredConstructors();
+        Constructor<T> mostArgConstructor = null;
+        int argCount = -1;
+        for (Constructor<T> constructor : constructors) {
+            if (constructor.isAnnotationPresent(Inject.class) || constructor.getParameterCount() == 0) {
+                if (constructor.getParameterCount() > argCount) {
+                    mostArgConstructor = constructor;
+                    argCount = constructor.getParameterCount();
+                }
+            }
+        }
+        return mostArgConstructor;
+    }
+
+    private Object[] getArguments(Executable executable, int argCount) {
+        if (executable == null) {
+            return null;
+        }
+        Object[] args = new Object[argCount];
+        for (int i = 0; i != argCount; i++) {
+            Type type = executable.getAnnotatedParameterTypes()[i].getType();
+            args[i] = isClass(type) ? getInstance((Class<?>) type) : getInstance(type);
+        }
+        return args;
+    }
+
+    private static void ensureAccessible(Executable executable) {
+        try {
+            if (!executable.isAccessible()) {
+                executable.setAccessible(true);
+            }
+        } catch (Exception e) {
+            // consume. It will fail later with invoking the executable
+        }
+    }
+
+    private void checkUnique(List<?> list) {
+        if (list.size() != 1) {
+            throw new IllegalStateException(LocalizationMessages.NONINJECT_AMBIGUOUS_SERVICES(list.get(0)));
+        }
+    }
+
+    @Override
+    public <T> T createAndInitialize(Class<T> createMe) {
+        return justCreate(createMe);
+    }
+
+    @Override
+    public void inject(Object injectMe) {
+        Method postConstruct = getAnnotatedMethod(injectMe, PostConstruct.class);
+        if (postConstruct != null) {
+            ensureAccessible(postConstruct);
+            try {
+                postConstruct.invoke(injectMe);
+            } catch (Exception e) {
+                throw new IllegalStateException(e);
+            }
+        }
+    }
+
+    @Override
+    public void inject(Object injectMe, String classAnalyzer) {
+        throw new UnsupportedOperationException("inject(Object injectMe, String classAnalyzer)");
+    }
+
+    @Override
+    public void preDestroy(Object preDestroyMe) {
+        Method preDestroy = getAnnotatedMethod(preDestroyMe, PreDestroy.class);
+        if (preDestroy != null) {
+            ensureAccessible(preDestroy);
+            try {
+                preDestroy.invoke(preDestroyMe);
+            } catch (Exception e) {
+                throw new IllegalStateException(e);
+            }
+        }
+    }
+
+    private static Method getAnnotatedMethod(Object object, Class<? extends Annotation> annotation) {
+        Class<?> clazz = object.getClass();
+        for (Method method : clazz.getMethods()) {
+            if (method.isAnnotationPresent(annotation)
+                    && /* do not invoke interceptors */ method.getParameterCount() == 0) {
+                return method;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Some {@link Binding} requires the proxy to be created rather than just the instance,
+     * for instance a proxy of an instance supplied by a supplier that is not known at a time of the proxy creation.
+     * @param createProxy the nullable {@link Binding#isProxiable()} information
+     * @param iface the type of which the proxy is created
+     * @param supplier the reference to the supplier
+     * @param <T> the type the supplier should supply
+     * @return The proxy for the instance supplied by a supplier or the instance if not required to be proxied.
+     */
+    @SuppressWarnings("unchecked")
+    private <T> T createSupplierProxyIfNeeded(Boolean createProxy, Class<T> iface, Supplier<T> supplier) {
+        if (createProxy != null && createProxy && iface.isInterface()) {
+            T proxy = (T) Proxy.newProxyInstance(iface.getClassLoader(), new Class[]{iface}, new InvocationHandler() {
+                final SingleRegisterSupplier<T> singleSupplierRegister = new SingleRegisterSupplier<>(supplier);
+                @Override
+                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+                    T t = singleSupplierRegister.get();
+                    Object ret = method.invoke(t, args);
+                    return ret;
+                }
+            });
+            return proxy;
+        } else {
+            return registerDisposableSupplierAndGet(supplier);
+        }
+    }
+
+    /**
+     * A holder class making sure the Supplier (especially the {@link DisposableSupplier}) supplying the instance
+     * supplies (and is registered for being disposed at the end of the lifecycle) only once.
+     * @param <T>
+     */
+    private class SingleRegisterSupplier<T> {
+        private final LazyValue<T> once;
+
+        private SingleRegisterSupplier(Supplier<T> supplier) {
+            once = Values.lazy((Value<T>) () -> registerDisposableSupplierAndGet(supplier));
+        }
+
+        T get() {
+            return once.get();
+        }
+    }
+
+    private <T> T registerDisposableSupplierAndGet(Supplier<T> supplier) {
+        T instance = supplier.get();
+        if (DisposableSupplier.class.isInstance(supplier)) {
+            disposableSupplierObjects.add((DisposableSupplier<T>) supplier, instance);
+        }
+        return instance;
+    }
+
+    /**
+     * Create {@link ClassBindings} instance containing bindings and instances for the given Type.
+     * @param clazz the given class.
+     * @param instancesQualifiers The qualifiers the expected instances of the given class should have.
+     * @param <T> Expected return class type.
+     * @return the {@link ClassBindings}.
+     */
+    @SuppressWarnings("unchecked")
+    private <T> ClassBindings<T> classBindings(Class<T> clazz, Annotation... instancesQualifiers) {
+        ClassBindings<T> classBindings = new ClassBindings<>(clazz, instancesQualifiers);
+        List<InstanceBinding<?>> ib = instanceBindings.get(clazz);
+        if (ib != null) {
+            ib.forEach(binding -> classBindings.instanceBindings.add((InstanceBinding<T>) binding));
+        }
+        List<SupplierInstanceBinding<?>> sib = supplierInstanceBindings.get(clazz);
+        if (sib != null) {
+            sib.forEach(binding -> classBindings.supplierInstanceBindings.add((SupplierInstanceBinding<T>) binding));
+        }
+        List<ClassBinding<?>> cb = contractBindings.get(clazz);
+        if (cb != null) {
+            cb.forEach(binding -> classBindings.classBindings.add((ClassBinding<T>) binding));
+        }
+        List<SupplierClassBinding<?>> scb = supplierClassBindings.get(clazz);
+        if (scb != null) {
+            scb.forEach(binding -> classBindings.supplierClassBindings.add((SupplierClassBinding<T>) binding));
+        }
+        return classBindings;
+    }
+
+    /**
+     * Create {@link TypeBindings} instance containing bindings and instances for the given Type.
+     * @param type the given type.
+     * @param <T> Expected return type.
+     * @return the {@link TypeBindings}.
+     */
+    @SuppressWarnings("unchecked")
+    private <T> TypeBindings<T> typeBindings(Type type) {
+        TypeBindings<T> typeBindings = new TypeBindings<>(type);
+        List<InstanceBinding<?>> ib = instanceTypeBindings.get(type);
+        if (ib != null) {
+            ib.forEach(binding -> typeBindings.instanceBindings.add((InstanceBinding<T>) binding));
+        }
+        List<SupplierInstanceBinding<?>> sib = supplierTypeInstanceBindings.get(type);
+        if (sib != null) {
+            sib.forEach(binding -> typeBindings.supplierInstanceBindings.add((SupplierInstanceBinding<T>) binding));
+        }
+        List<ClassBinding<?>> cb = contractTypeBindings.get(type);
+        if (cb != null) {
+            cb.forEach(binding -> typeBindings.classBindings.add((ClassBinding<T>) binding));
+        }
+        List<SupplierClassBinding<?>> scb = supplierTypeClassBindings.get(type);
+        if (scb != null) {
+            scb.forEach(binding -> typeBindings.supplierClassBindings.add((SupplierClassBinding<T>) binding));
+        }
+        return typeBindings;
+    }
+
+    /**
+     * <p>
+     * A class that contains relevant bindings for a given TYPE, filtered from all registered bindings.
+     * The TYPE is either Type (ParametrizedType) or Class.
+     * </p>
+     * <p>
+     * The class also filters any bindings for which the singleton or thread-scoped instance already is created.
+     * The class either provides the existing instance, or all instances of the TYPE, or {@link ServiceHolder}s.
+     * </p>
+     * @param <X> The expected return type for the TYPE.
+     * @param <TYPE> The Type for which a {@link Binding} has been created.
+     */
+    private abstract class XBindings<X, TYPE> {
+
+        protected final List<InstanceBinding<X>> instanceBindings = new LinkedList<>();
+        protected final List<SupplierInstanceBinding<X>> supplierInstanceBindings = new LinkedList<>();
+        protected final List<ClassBinding<X>> classBindings = new LinkedList<>();
+        protected final List<SupplierClassBinding<X>> supplierClassBindings = new LinkedList<>();
+
+        protected final TYPE type;
+        protected final Annotation[] instancesQualifiers;
+        protected final TypedInstances<TYPE> instances;
+
+        protected XBindings(TYPE type, Annotation[] instancesQualifiers, TypedInstances<TYPE> instances) {
+            this.type = type;
+            this.instancesQualifiers = instancesQualifiers;
+            this.instances = instances;
+        }
+
+        int size() {
+            return instanceBindings.size()
+                    + supplierInstanceBindings.size()
+                    + classBindings.size()
+                    + supplierClassBindings.size();
+        }
+
+        private void _checkUnique() {
+            if (size() > 1) {
+                throw new IllegalStateException(LocalizationMessages.NONINJECT_AMBIGUOUS_SERVICES(type));
+            }
+        }
+
+        void filterBinding(Binding binding) {
+            if (InstanceBinding.class.isInstance(binding)) {
+                instanceBindings.remove(binding);
+            } else if (ClassBinding.class.isInstance(binding)) {
+                classBindings.remove(binding);
+            } else if (SupplierInstanceBinding.class.isInstance(binding)) {
+                supplierInstanceBindings.remove(binding);
+            } else if (SupplierClassBinding.class.isInstance(binding)) {
+                supplierClassBindings.remove(binding);
+            }
+        }
+
+        /**
+         * Match the binging qualifiers
+         * @param bindingQualifiers the qualifiers registered with the bindings
+         */
+        void matchQualifiers(Annotation... bindingQualifiers) {
+            if (bindingQualifiers != null) {
+                _filterRequested(instanceBindings, bindingQualifiers);
+                _filterRequested(classBindings, bindingQualifiers);
+                _filterRequested(supplierInstanceBindings, bindingQualifiers);
+                _filterRequested(supplierClassBindings, bindingQualifiers);
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        private void _filterRequested(List<? extends Binding<?, ?>> bindingList, Annotation... requestedQualifiers) {
+            for (Iterator<? extends Binding> bindingIterator = bindingList.iterator(); bindingIterator.hasNext();) {
+                Binding<X, ?> binding = bindingIterator.next();
+                classLoop:
+                for (Annotation requestedQualifier : requestedQualifiers) {
+                    for (Annotation bindingQualifier : binding.getQualifiers()) {
+                        if (requestedQualifier.annotationType().isInstance(bindingQualifier)) {
+                            continue classLoop;
+                        }
+                    }
+                    bindingIterator.remove();
+                }
+            }
+        }
+
+        protected boolean _isPerThread(Class<? extends Annotation> scope) {
+            return RequestScoped.class.equals(scope) || PerThread.class.equals(scope);
+        }
+
+        private X _getInstance(InstanceBinding<X> instanceBinding) {
+            return instanceBinding.getService();
+        }
+
+        private X _create(SupplierInstanceBinding<X> binding) {
+            Supplier<X> supplier = binding.getSupplier();
+            X t = registerDisposableSupplierAndGet(supplier);
+            if (Singleton.class.equals(binding.getScope())) {
+                _addInstance(t, binding);
+            } else if (_isPerThread(binding.getScope())) {
+                _addThreadInstance(t, binding);
+            }
+            return t;
+        }
+
+        X create() {
+            _checkUnique();
+            if (!instanceBindings.isEmpty()) {
+                return _getInstance(instanceBindings.get(0));
+            } else if (!supplierInstanceBindings.isEmpty()) {
+                return _create(supplierInstanceBindings.get(0));
+            } else if (!classBindings.isEmpty()) {
+                return _createAndStore(classBindings.get(0));
+            } else if (!supplierClassBindings.isEmpty()) {
+                return _create(supplierClassBindings.get(0));
+            }
+
+            throw new IllegalStateException(LocalizationMessages.NONINJECT_NO_BINDING(type));
+        }
+
+        protected X getInstance() {
+            X instance = instances.getInstance(type, instancesQualifiers);
+            if (instance != null) {
+                return instance;
+            }
+            return create();
+        }
+
+        List<X> allInstances() {
+            List<X> list = new LinkedList<>();
+            List<InstanceContext<?>> instanceContextList;
+
+            instanceContextList = instances.getContexts(type, instancesQualifiers);
+            if (instanceContextList != null) {
+                instanceContextList.forEach(instanceContext -> filterBinding(instanceContext.getBinding()));
+                instanceContextList.forEach(instanceContext -> list.add((X) instanceContext.getInstance()));
+            }
+
+            list.addAll(instanceBindings.stream()
+                    .map(this::_getInstance)
+                    .collect(Collectors.toList()));
+
+            list.addAll(classBindings.stream()
+                    .map(this::_createAndStore)
+                    .collect(Collectors.toList()));
+
+            list.addAll(supplierInstanceBindings.stream()
+                    .map(this::_create)
+                    .collect(Collectors.toList()));
+
+            list.addAll(supplierClassBindings.stream()
+                    .map(this::_create)
+                    .collect(Collectors.toList()));
+
+            return list;
+        }
+
+        protected abstract X _create(SupplierClassBinding<X> binding);
+
+        protected abstract X _createAndStore(ClassBinding<X> binding);
+
+        protected <T> T _addInstance(TYPE type, T instance, Binding<?, ?> binding) {
+            return instances.addSingleton(type, instance, binding, instancesQualifiers);
+        }
+
+        protected void _addThreadInstance(TYPE type, Object instance, Binding binding) {
+            instances.addThreadInstance(type, instance, binding, instancesQualifiers);
+        }
+
+        protected <T> T _addInstance(T instance, Binding<?, ?> binding) {
+            return instances.addSingleton(type, instance, binding, instancesQualifiers);
+        }
+
+        protected void _addThreadInstance(Object instance, Binding binding) {
+            instances.addThreadInstance(type, instance, binding, instancesQualifiers);
+        }
+    }
+
+
+    private class ClassBindings<T> extends XBindings<T, Class<?>> {
+        private ClassBindings(Class<T> clazz, Annotation[] instancesQualifiers) {
+            super(clazz, instancesQualifiers, NonInjectionManager.this.instances);
+        }
+
+        @SuppressWarnings("unchecked")
+        List<ServiceHolder<T>> getAllServiceHolders(Annotation... qualifiers) {
+            matchQualifiers(qualifiers);
+
+            List<ServiceHolder<T>> holders = new LinkedList<>();
+            List<InstanceContext<?>> instanceContextList;
+
+            instanceContextList = instances.getContexts(type, qualifiers);
+
+            if (instanceContextList != null) {
+                instanceContextList.forEach(instanceContext -> filterBinding(instanceContext.getBinding()));
+                instanceContextList.forEach(instanceContext -> holders.add(new ServiceHolderImpl<T>(
+                        (T) instanceContext.getInstance(),
+                        (Class<T>) instanceContext.getInstance().getClass(),
+                        instanceContext.getBinding().getContracts(),
+                        instanceContext.getBinding().getRank() == null ? 0 : instanceContext.getBinding().getRank())
+                ));
+            }
+
+            List<ServiceHolder<T>> instanceBindingHolders = instanceBindings.stream()
+                    .map(this::_serviceHolder)
+                    .collect(Collectors.toList());
+            holders.addAll(instanceBindingHolders);
+
+            List<ServiceHolder<T>> classBindingHolders = classBindings.stream()
+                    .filter(binding -> NonInjectionManager.this.findConstructor(binding.getService()) != null)
+                    .map(this::_serviceHolder)
+                    .collect(Collectors.toList());
+            holders.addAll(classBindingHolders);
+
+            return holders;
+        }
+
+        private <T> ServiceHolderImpl<T> _serviceHolder(InstanceBinding<T> binding) {
+            return new ServiceHolderImpl<T>(
+                    binding.getService(),
+                    binding.getImplementationType(),
+                    binding.getContracts(),
+                    binding.getRank() == null ? 0 : binding.getRank());
+        }
+
+        private <T> ServiceHolderImpl<T> _serviceHolder(ClassBinding<T> binding) {
+            return new ServiceHolderImpl<T>(
+                    NonInjectionManager.this.create(binding.getService()),
+                    binding.getImplementationType(),
+                    binding.getContracts(),
+                    binding.getRank() == null ? 0 : binding.getRank());
+        }
+
+        protected T _create(SupplierClassBinding<T> binding) {
+            Supplier<T> supplier = instances.getInstance(binding.getSupplierClass(), null);
+            if (supplier == null) {
+                supplier = justCreate(binding.getSupplierClass());
+                if (Singleton.class.equals(binding.getSupplierScope())) {
+                    supplier = instances.addSingleton(binding.getSupplierClass(), supplier, binding, null);
+                } else if (_isPerThread(binding.getSupplierScope())) {
+                    instances.addThreadInstance(binding.getSupplierClass(), supplier, binding, null);
+                }
+            }
+
+            T t = createSupplierProxyIfNeeded(binding.isProxiable(), (Class<T>) type, supplier);
+            if (Singleton.class.equals(binding.getScope())) {
+                t = _addInstance(type, t, binding);
+            } else if (_isPerThread(binding.getScope())) {
+                _addThreadInstance(type, t, binding);
+            }
+            return t;
+        }
+
+        protected T _createAndStore(ClassBinding<T> binding) {
+            T result = justCreate(binding.getService());
+            result = _addInstance(binding.getService(), result, binding);
+            return result;
+        }
+    }
+
+    private class TypeBindings<T> extends XBindings<T, Type> {
+        private TypeBindings(Type type) {
+            super(type, null, types);
+        }
+
+        protected T _create(SupplierClassBinding<T> binding) {
+            Supplier<T> supplier = justCreate(binding.getSupplierClass());
+
+            T t = registerDisposableSupplierAndGet(supplier);
+            if (Singleton.class.equals(binding.getScope())) {
+                t = _addInstance(type, t, binding);
+            } else if (_isPerThread(binding.getScope())) {
+                _addThreadInstance(type, t, binding);
+            }
+            return t;
+        }
+
+        @Override
+        protected T _createAndStore(ClassBinding<T> binding) {
+            T result = justCreate(binding.getService());
+            result = _addInstance(type, result, binding);
+            return result;
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        T create() {
+            if (ParameterizedType.class.isInstance(type)) {
+                ParameterizedType pt = (ParameterizedType) type;
+                if (Provider.class.equals(pt.getRawType())) {
+                    return (T) new Provider<Object>() {
+                        final SingleRegisterSupplier<Object> supplier = new SingleRegisterSupplier<>(new Supplier<Object>() {
+                            @Override
+                            public Object get() {
+                                Type actualTypeArgument = pt.getActualTypeArguments()[0];
+                                if (isClass(actualTypeArgument)) {
+                                    return NonInjectionManager.this.getInstance((Class<? extends T>) actualTypeArgument);
+                                } else {
+                                    return NonInjectionManager.this.getInstance(actualTypeArgument);
+                                }
+                            }
+                        });
+
+                        @Override
+                        public Object get() {
+                            return supplier.get(); //Not disposable
+                        }
+                    };
+                }
+            }
+            return super.create();
+        }
+    }
+
+    /**
+     * A triplet of created instance, the registered {@link Binding} that prescribed the creation of the instance
+     * and {@link Annotation qualifiers} the instance was created with.
+     * @param <T> type of the instance.
+     * @see NonInjectionManager#getInstance(Class, Annotation[])
+     */
+    private static class InstanceContext<T> {
+        private final T instance;
+        private final Binding<?, ?> binding;
+        private final Annotation[] createdWithQualifiers;
+
+        private InstanceContext(T instance, Binding<?, ?> binding, Annotation[] qualifiers) {
+            this.instance = instance;
+            this.binding = binding;
+            this.createdWithQualifiers = qualifiers;
+        }
+
+        public Binding<?, ?> getBinding() {
+            return binding;
+        }
+
+        public T getInstance() {
+            return instance;
+        }
+
+        @SuppressWarnings("unchecked")
+        static <T> List<T> toInstances(List<InstanceContext<?>> instances, Annotation[] qualifiers) {
+            return instances != null
+                    ? instances.stream()
+                        .filter(instance -> instance.hasQualifiers(qualifiers))
+                        .map(pair -> (T) pair.getInstance())
+                        .collect(Collectors.toList())
+                    : null;
+        }
+
+        private static List<InstanceContext<?>> filterInstances(List<InstanceContext<?>> instances, Annotation... qualifiers) {
+            return instances != null
+                    ? instances.stream()
+                        .filter(instance -> instance.hasQualifiers(qualifiers))
+                        .collect(Collectors.toList())
+                    : null;
+        }
+
+        private boolean hasQualifiers(Annotation[] requested) {
+            if (requested != null) {
+                classLoop:
+                for (Annotation req : requested) {
+                    if (createdWithQualifiers != null) {
+                        for (Annotation cur : createdWithQualifiers) {
+                            if (cur.annotationType().isInstance(req)) {
+                                continue classLoop;
+                            }
+                        }
+                        return false;
+                    }
+                }
+            }
+            return true;
+        }
+    }
+
+    /**
+     * Singleton Binding this {@link NonInjectionManager} was supposed to be created based upon.
+     */
+    private static final class InjectionManagerBinding extends Binding<InjectionManager, Binding<?, ?>> {
+    }
+
+}
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/innate/inject/NonInjectionRequestScope.java b/core-client/src/main/java/org/glassfish/jersey/client/innate/inject/NonInjectionRequestScope.java
new file mode 100644
index 0000000..258780d
--- /dev/null
+++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/inject/NonInjectionRequestScope.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2023 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.inject;
+
+import org.glassfish.jersey.internal.util.ExtendedLogger;
+import org.glassfish.jersey.internal.util.LazyUid;
+import org.glassfish.jersey.process.internal.RequestScope;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class NonInjectionRequestScope extends RequestScope {
+    @Override
+    public org.glassfish.jersey.process.internal.RequestContext createContext() {
+        return new Instance();
+    }
+
+    /**
+     * Implementation of the request scope instance.
+     */
+    public static final class Instance implements org.glassfish.jersey.process.internal.RequestContext {
+
+        private static final ExtendedLogger logger = new ExtendedLogger(Logger.getLogger(Instance.class.getName()), Level.FINEST);
+
+        /*
+         * Scope instance UUID.
+         *
+         * For performance reasons, it's only generated if toString() method is invoked,
+         * e.g. as part of some low-level logging.
+         */
+        private final LazyUid id = new LazyUid();
+
+        /**
+         * Holds the number of snapshots of this scope.
+         */
+        private final AtomicInteger referenceCounter;
+
+        private Instance() {
+            this.referenceCounter = new AtomicInteger(1);
+        }
+
+        /**
+         * Get a "new" reference of the scope instance. This will increase
+         * the internal reference counter which prevents the scope instance
+         * to be destroyed until a {@link #release()} method is explicitly
+         * called (once per each {@code getReference()} method call).
+         *
+         * @return referenced scope instance.
+         */
+        @Override
+        public NonInjectionRequestScope.Instance getReference() {
+            // TODO: replace counter with a phantom reference + reference queue-based solution
+            referenceCounter.incrementAndGet();
+            return this;
+        }
+
+
+        /**
+         * Release a single reference to the current request scope instance.
+         * <p>
+         * Once all instance references are released, the instance will be recycled.
+         */
+        @Override
+        public void release() {
+            referenceCounter.decrementAndGet();
+        }
+
+        @Override
+        public String toString() {
+            return "Instance{"
+                    + "id=" + id
+                    + ", referenceCounter=" + referenceCounter
+                    + '}';
+        }
+    }
+}
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 31a3583..c7e0ac2 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, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2023 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
@@ -21,10 +21,13 @@
 import java.io.InputStream;
 import java.lang.reflect.Field;
 import java.net.HttpURLConnection;
+import java.net.InetAddress;
 import java.net.ProtocolException;
+import java.net.Socket;
 import java.net.SocketTimeoutException;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.net.UnknownHostException;
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
@@ -42,6 +45,7 @@
 
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSocket;
 import javax.net.ssl.SSLSocketFactory;
 import jakarta.ws.rs.ProcessingException;
 import jakarta.ws.rs.client.Client;
@@ -55,6 +59,7 @@
 import org.glassfish.jersey.client.JerseyClient;
 import org.glassfish.jersey.client.RequestEntityProcessing;
 import org.glassfish.jersey.client.innate.ClientProxy;
+import org.glassfish.jersey.client.innate.http.SSLParamConfigurator;
 import org.glassfish.jersey.client.spi.AsyncConnectorCallback;
 import org.glassfish.jersey.client.spi.Connector;
 import org.glassfish.jersey.internal.util.PropertiesHelper;
@@ -315,11 +320,35 @@
         }
     }
 
+    /**
+     * Secure connection if necessary.
+     * <p/>
+     * Provided implementation sets {@link HostnameVerifier} and {@link SSLSocketFactory} to give connection, if that
+     * is an instance of {@link HttpsURLConnection}.
+     *
+     * @param clientRequest the actual client request.
+     * @param uc     http connection to be secured.
+     */
+    private void secureConnection(
+            final ClientRequest clientRequest, final HttpURLConnection uc, final SSLParamConfigurator sniConfig) {
+        secureConnection(clientRequest.getClient(), uc); // keep this for compatibility
+
+        if (sniConfig.isSNIRequired() && uc instanceof HttpsURLConnection) { // set SNI
+            HttpsURLConnection suc = (HttpsURLConnection) uc;
+            SniSSLSocketFactory socketFactory = new SniSSLSocketFactory(suc.getSSLSocketFactory());
+            socketFactory.setSniConfig(sniConfig);
+            suc.setSSLSocketFactory(socketFactory);
+        }
+    }
+
     private ClientResponse _apply(final ClientRequest request) throws IOException {
         final HttpURLConnection uc;
-        Optional<ClientProxy> proxy = ClientProxy.proxyFromRequest(request);
+        final Optional<ClientProxy> proxy = ClientProxy.proxyFromRequest(request);
+        final SSLParamConfigurator sniConfig = SSLParamConfigurator.builder().request(request).build();
+        final URI sniUri = sniConfig.isSNIRequired() ? sniConfig.toIPRequestUri() : request.getUri();
+
         proxy.ifPresent(clientProxy -> ClientProxy.setBasicAuthorizationHeader(request.getHeaders(), proxy.get()));
-        uc = this.connectionFactory.getConnection(request.getUri().toURL(), proxy.isPresent() ? proxy.get().proxy() : null);
+        uc = this.connectionFactory.getConnection(sniUri.toURL(), proxy.isPresent() ? proxy.get().proxy() : null);
         uc.setDoInput(true);
 
         final String httpMethod = request.getMethod();
@@ -335,7 +364,7 @@
 
         uc.setReadTimeout(request.resolveProperty(ClientProperties.READ_TIMEOUT, uc.getReadTimeout()));
 
-        secureConnection(request.getClient(), uc);
+        secureConnection(request, uc, sniConfig);
 
         final Object entity = request.getEntity();
         Exception storedException = null;
@@ -559,4 +588,84 @@
     public String getName() {
         return "HttpUrlConnection " + AccessController.doPrivileged(PropertiesHelper.getSystemProperty("java.version"));
     }
+
+    private static class SniSSLSocketFactory extends SSLSocketFactory {
+        private final SSLSocketFactory socketFactory;
+        private ThreadLocal<SSLParamConfigurator> sniConfigs = new ThreadLocal<>();
+
+        public void setSniConfig(SSLParamConfigurator sniConfigs) {
+            this.sniConfigs.set(sniConfigs);
+        }
+
+        private SniSSLSocketFactory(SSLSocketFactory socketFactory) {
+            this.socketFactory = socketFactory;
+        }
+
+        @Override
+        public String[] getDefaultCipherSuites() {
+            return socketFactory.getDefaultCipherSuites();
+        }
+
+        @Override
+        public String[] getSupportedCipherSuites() {
+            return socketFactory.getSupportedCipherSuites();
+        }
+
+        @Override
+        public Socket createSocket(Socket socket, String s, int i, boolean b) throws IOException {
+            Socket superSocket = socketFactory.createSocket(socket, s, i, b);
+            setSNIServerName(superSocket);
+            return superSocket;
+        }
+
+        @Override
+        public Socket createSocket(String s, int i) throws IOException, UnknownHostException {
+            Socket superSocket = socketFactory.createSocket(s, i);
+            setSNIServerName(superSocket);
+            return superSocket;
+        }
+
+        @Override
+        public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) throws IOException, UnknownHostException {
+            Socket superSocket = socketFactory.createSocket(s, i, inetAddress, i1);
+            setSNIServerName(superSocket);
+            return superSocket;
+        }
+
+        @Override
+        public Socket createSocket(InetAddress inetAddress, int i) throws IOException {
+            Socket superSocket = socketFactory.createSocket(inetAddress, i);
+            setSNIServerName(superSocket);
+            return superSocket;
+        }
+
+        @Override
+        public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException {
+            Socket superSocket = socketFactory.createSocket(inetAddress, i, inetAddress1, i1);
+            setSNIServerName(superSocket);
+            return superSocket;
+        }
+
+        @Override
+        public Socket createSocket(Socket s, InputStream consumed, boolean autoClose) throws IOException {
+            Socket superSocket = socketFactory.createSocket(s, consumed, autoClose);
+            setSNIServerName(superSocket);
+            return superSocket;
+        }
+
+        @Override
+        public Socket createSocket() throws IOException {
+            Socket superSocket = socketFactory.createSocket();
+            setSNIServerName(superSocket);
+            return superSocket;
+        }
+
+        private void setSNIServerName(Socket superSocket) {
+            SSLParamConfigurator sniConfig = this.sniConfigs.get();
+            if (null != sniConfig && SSLSocket.class.isInstance(superSocket)) {
+                sniConfig.setSNIServerName((SSLSocket) superSocket);
+            }
+            this.sniConfigs.remove();
+        }
+    }
 }
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 e66ceab..ee80184 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, 2022 Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 2023 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
@@ -48,7 +48,14 @@
   Using default cached thread pool.
 negative.chunk.size=Negative chunked HTTP transfer coding chunk size value specified in the client configuration property: [{0}] \
   Reverting to programmatically set default: [{1}]
-negative.input.parameter="Input parameter {0} must not be negative."
+negative.input.parameter="Input parameter {0} must not be negative1."
+noninject.ambiguous.services=Ambiguous providing services ${0}.
+noninject.fallback=Falling back to injection-less client.
+noninject.no.constructor=No applicable constructor for ${0} found.
+noninject.no.binding=No binding found for ${0}.
+noninject.requestscope.created=RequestScope already created.
+noninject.shutdown=InjectionManager is already shutdown.
+noninject.unsatisfied=Unsatisfied dependency for ${0}.
 null.connector.provider=ConnectorProvider must not be set to null.
 null.executor.service=ExecutorService must not be set to null.
 null.input.parameter=Input method parameter {0} must not be null.
diff --git a/core-client/src/test/java/org/glassfish/jersey/client/ClientConfigTest.java b/core-client/src/test/java/org/glassfish/jersey/client/ClientConfigTest.java
index 8ab88e7..aaa88c9 100644
--- a/core-client/src/test/java/org/glassfish/jersey/client/ClientConfigTest.java
+++ b/core-client/src/test/java/org/glassfish/jersey/client/ClientConfigTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 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
@@ -112,7 +112,7 @@
     }
 
     @Provider
-    public class MyProvider implements ContextResolver<String> {
+    public static class MyProvider implements ContextResolver<String> {
 
         @Override
         public String getContext(final Class<?> type) {
diff --git a/core-client/src/test/java/org/glassfish/jersey/client/JerseyClientTest.java b/core-client/src/test/java/org/glassfish/jersey/client/JerseyClientTest.java
index 05ac6ea..a985579 100644
--- a/core-client/src/test/java/org/glassfish/jersey/client/JerseyClientTest.java
+++ b/core-client/src/test/java/org/glassfish/jersey/client/JerseyClientTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2023 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
@@ -272,8 +272,12 @@
     }
 
     public static class CustomProvider implements ClientRequestFilter {
+        private final CustomContract customContract;
+
         @Inject
-        private CustomContract customContract;
+        CustomProvider(CustomContract customContract) {
+            this.customContract = customContract;
+        }
 
         @Override
         public void filter(ClientRequestContext requestContext) throws IOException {
diff --git a/core-client/src/test/java/org/glassfish/jersey/client/JerseyCompletionStageRxInvokerTest.java b/core-client/src/test/java/org/glassfish/jersey/client/JerseyCompletionStageRxInvokerTest.java
index d7643aa..515bb83 100644
--- a/core-client/src/test/java/org/glassfish/jersey/client/JerseyCompletionStageRxInvokerTest.java
+++ b/core-client/src/test/java/org/glassfish/jersey/client/JerseyCompletionStageRxInvokerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2023 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
@@ -34,7 +34,6 @@
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.containsString;
@@ -71,7 +70,6 @@
     }
 
     @Test
-    @Disabled("TODO JAX-RS 2.1")
     public void testNewClientExecutor() throws Exception {
         testClient(ClientBuilder.newBuilder()
                                 .executorService(executor)
diff --git a/core-client/src/test/java/org/glassfish/jersey/client/spi/PreInvocationInterceptorTest.java b/core-client/src/test/java/org/glassfish/jersey/client/spi/PreInvocationInterceptorTest.java
index 2df0307..deafb62 100644
--- a/core-client/src/test/java/org/glassfish/jersey/client/spi/PreInvocationInterceptorTest.java
+++ b/core-client/src/test/java/org/glassfish/jersey/client/spi/PreInvocationInterceptorTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2023 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,13 +22,13 @@
 import org.junit.jupiter.api.Test;
 
 import jakarta.annotation.Priority;
+import jakarta.inject.Inject;
 import jakarta.ws.rs.ProcessingException;
 import jakarta.ws.rs.client.ClientBuilder;
 import jakarta.ws.rs.client.ClientRequestContext;
 import jakarta.ws.rs.client.ClientRequestFilter;
 import jakarta.ws.rs.client.Invocation;
 import jakarta.ws.rs.core.Configuration;
-import jakarta.ws.rs.core.Context;
 import jakarta.ws.rs.core.Response;
 import java.io.IOException;
 import java.util.concurrent.ExecutionException;
@@ -263,8 +263,12 @@
     }
 
     private static class InjectedPreInvocationInterceptor implements PreInvocationInterceptor {
-        @Context
-        Configuration configuration;
+        private final Configuration configuration;
+
+        @Inject
+        public InjectedPreInvocationInterceptor(Configuration configuration) {
+            this.configuration = configuration;
+        }
 
         @Override
         public void beforeRequest(ClientRequestContext requestContext) {
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/JaxrsProviders.java b/core-common/src/main/java/org/glassfish/jersey/internal/JaxrsProviders.java
index bc5c722..57c7d24 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/JaxrsProviders.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/JaxrsProviders.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 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
@@ -62,12 +62,18 @@
         }
     }
 
+    private final Provider<MessageBodyWorkers> workers;
+    private final Provider<ContextResolvers> resolvers;
+    private final Provider<ExceptionMappers> mappers;
+
     @Inject
-    private Provider<MessageBodyWorkers> workers;
-    @Inject
-    private Provider<ContextResolvers> resolvers;
-    @Inject
-    private Provider<ExceptionMappers> mappers;
+    public JaxrsProviders(Provider<MessageBodyWorkers> workers,
+                          Provider<ContextResolvers> resolvers,
+                          Provider<ExceptionMappers> mappers) {
+        this.workers = workers;
+        this.resolvers = resolvers;
+        this.mappers = mappers;
+    }
 
     @Override
     public <T> MessageBodyReader<T> getMessageBodyReader(Class<T> type,
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/inject/Injections.java b/core-common/src/main/java/org/glassfish/jersey/internal/inject/Injections.java
index 19177cf..1750dd8 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/inject/Injections.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/inject/Injections.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 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
@@ -20,6 +20,8 @@
 import java.util.List;
 import java.util.Optional;
 
+import jakarta.ws.rs.ConstrainedTo;
+import jakarta.ws.rs.RuntimeType;
 import jakarta.ws.rs.WebApplicationException;
 
 import org.glassfish.jersey.internal.LocalizationMessages;
@@ -36,22 +38,32 @@
 public class Injections {
 
     /**
-     * Creates a {@link InjectionManager} without parent and initial binder.
+     * Creates an {@link InjectionManager} without parent and initial binder.
      *
-     * @return a injection manager with all the bindings.
+     * @return an injection manager with all the bindings.
      */
     public static InjectionManager createInjectionManager() {
-        return lookupInjectionManagerFactory().create();
+        return lookupInjectionManagerFactory(RuntimeType.SERVER).create();
+    }
+
+    /**
+     * Creates an {@link InjectionManager} without parent and initial binder.
+     * @param type {@link RuntimeType} the {@link InjectionManagerFactory} must be {@link ConstrainedTo} if annotated.
+     *
+     * @return an injection manager with all the bindings.
+     */
+    public static InjectionManager createInjectionManager(RuntimeType type) {
+        return lookupInjectionManagerFactory(type).create();
     }
 
     /**
      * Creates a {@link InjectionManager} with initial binder that is immediately registered.
      *
      * @param binder custom the {@link Binder binder}.
-     * @return a injection manager with all the bindings.
+     * @return an injection manager with all the bindings.
      */
     public static InjectionManager createInjectionManager(Binder binder) {
-        InjectionManagerFactory injectionManagerFactory = lookupInjectionManagerFactory();
+        InjectionManagerFactory injectionManagerFactory = lookupInjectionManagerFactory(RuntimeType.SERVER);
         InjectionManager injectionManager = injectionManagerFactory.create();
         injectionManager.register(binder);
         return injectionManager;
@@ -66,11 +78,11 @@
      * @return an injection manager with all the bindings.
      */
     public static InjectionManager createInjectionManager(Object parent) {
-        return lookupInjectionManagerFactory().create(parent);
+        return lookupInjectionManagerFactory(RuntimeType.SERVER).create(parent);
     }
 
-    private static InjectionManagerFactory lookupInjectionManagerFactory() {
-        return lookupService(InjectionManagerFactory.class)
+    private static InjectionManagerFactory lookupInjectionManagerFactory(RuntimeType type) {
+        return lookupService(InjectionManagerFactory.class, type)
                 .orElseThrow(() -> new IllegalStateException(LocalizationMessages.INJECTION_MANAGER_FACTORY_NOT_FOUND()));
     }
 
@@ -80,12 +92,17 @@
      *
      * @param clazz type of service to look for.
      * @param <T>   type of service to look for.
+     * @param type {@link RuntimeType} the {@link InjectionManagerFactory} must be {@link ConstrainedTo} if annotated.
      * @return instance of service with highest priority or {@code null} if service of given type cannot be found.
      * @see jakarta.annotation.Priority
      */
-    private static <T> Optional<T> lookupService(final Class<T> clazz) {
+    private static <T> Optional<T> lookupService(final Class<T> clazz, RuntimeType type) {
         List<RankedProvider<T>> providers = new LinkedList<>();
         for (T provider : ServiceFinder.find(clazz)) {
+            ConstrainedTo constrain = provider.getClass().getAnnotation(ConstrainedTo.class);
+            if (constrain != null && type != constrain.value()) {
+                continue;
+            }
             providers.add(new RankedProvider<>(provider));
         }
         providers.sort(new RankedComparator<>(RankedComparator.Order.DESCENDING));
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/SourceProvider.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/SourceProvider.java
index d30f655..8d6a8ef 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/SourceProvider.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/SourceProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 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,11 +22,11 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
 
+import jakarta.inject.Inject;
 import jakarta.ws.rs.BadRequestException;
 import jakarta.ws.rs.Consumes;
 import jakarta.ws.rs.InternalServerErrorException;
 import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.core.Context;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.MultivaluedMap;
 import jakarta.ws.rs.ext.MessageBodyReader;
@@ -95,7 +95,8 @@
 
         private final Provider<SAXParserFactory> spf;
 
-        public SaxSourceReader(@Context Provider<SAXParserFactory> spf) {
+        @Inject
+        public SaxSourceReader(Provider<SAXParserFactory> spf) {
             this.spf = spf;
         }
 
@@ -135,7 +136,8 @@
 
         private final Provider<DocumentBuilderFactory> dbf;
 
-        public DomSourceReader(@Context Provider<DocumentBuilderFactory> dbf) {
+        @Inject
+        public DomSourceReader(Provider<DocumentBuilderFactory> dbf) {
             this.dbf = dbf;
         }
 
@@ -176,8 +178,9 @@
         private final Provider<SAXParserFactory> saxParserFactory;
         private final Provider<TransformerFactory> transformerFactory;
 
-        public SourceWriter(@Context Provider<SAXParserFactory> spf,
-                @Context Provider<TransformerFactory> tf) {
+        @Inject
+        public SourceWriter(Provider<SAXParserFactory> spf,
+                            Provider<TransformerFactory> tf) {
             this.saxParserFactory = spf;
             this.transformerFactory = tf;
         }
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/AnnotationAcceptingListener.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/AnnotationAcceptingListener.java
index c8c9684..e85d57a 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/AnnotationAcceptingListener.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/AnnotationAcceptingListener.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 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
@@ -319,7 +319,7 @@
 
         private void accept(final ClassVisitor classVisitor, final int parsingOptions) {
             final int originalVersion = getMajorVersion(b);
-            if (originalVersion == WARN_VERSION + 1) {
+            if (originalVersion > WARN_VERSION) {
                 // temporarily downgrade version to bypass check in ASM
                 setMajorVersion(WARN_VERSION, b);
                 LOGGER.warning("Unsupported class file major version " + originalVersion);
diff --git a/docs/src/main/docbook/client.xml b/docs/src/main/docbook/client.xml
index 1ba38d2..e19ffe0 100644
--- a/docs/src/main/docbook/client.xml
+++ b/docs/src/main/docbook/client.xml
@@ -1087,8 +1087,22 @@
             <para>
                 See javadoc of the &jersey.client.HttpAuthenticationFeature; for more details.
             </para>
-    </section>
+        </section>
 
+        <section>
+            <title><anchor xml:id="SNI"/>Server Name Indication (SNI) Support</title>
+            <para>
+                When using SSL/TLS protocols for the connection, <literal>SNIHostName</literal> is set automatically
+                based on the host name in the HTTPS request.
+            </para>
+            <para>
+                There might be use-cases where the <literal>SNIHostName</literal> is required to be set for other host
+                than the host specified in the HTTPS request. For those cases, when the HTTP header <literal>Host</literal>
+                is set, the <literal>SNIHostName</literal> is set for the host specified in the <literal>Host</literal> header.
+                Note that only <literal>Apache Connector, JDK Connector, Netty connector</literal>, and the default
+                <literal>HttpUrlConnector</literal> do support this feature.
+            </para>
+        </section>
 
     </section>
 
diff --git a/etc/config/copyright-exclude b/etc/config/copyright-exclude
index 987175b..9577477 100644
--- a/etc/config/copyright-exclude
+++ b/etc/config/copyright-exclude
@@ -69,6 +69,7 @@
 /tests/e2e/server/mvc/MvcEncodingTest/MustacheResource.mustache
 /test/resources/org/glassfish/jersey/server/config/jaxrs-components
 /tests/e2e-entity/src/test/resources/org/glassfish/jersey/tests/e2e/entity/xxe.txt
+/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/explorer
 /core-server/src/main/java/com/sun/research/ws/wadl
 /core-common/src/main/java/org/glassfish/jersey/internal/jsr166
 /core-common/src/main/jsr166/org/glassfish/jersey/internal/jsr166
diff --git a/examples/NOTICE.md b/examples/NOTICE.md
index 84c7087..71390cd 100644
--- a/examples/NOTICE.md
+++ b/examples/NOTICE.md
@@ -43,6 +43,11 @@
 * Copyright: 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
 * by the @authors tag.
 
+Hibernate Validator CDI, 7.0.5.Final
+* License: Apache License, 2.0
+* Project: https://beanvalidation.org/
+* Repackaged in org.glassfish.jersey.server.validation.internal.hibernate
+
 Bootstrap v3.3.7
 * License: MIT license (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * Project: http://getbootstrap.com
@@ -61,12 +66,12 @@
 * License: Apache License, 2.0
 * Copyright (C) 2009 The JSR-330 Expert Group
 
-Javassist Version 3.25.0-GA
+Javassist Version 3.29.0-GA
 * License: Apache License, 2.0
 * Project: http://www.javassist.org/
 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
 
-Jackson JAX-RS Providers Version 2.11.3
+Jackson JAX-RS Providers Version 2.14.1
 * License: Apache License, 2.0
 * Project: https://github.com/FasterXML/jackson-jaxrs-providers
 * Copyright: (c) 2009-2011 FasterXML, LLC. All rights reserved unless otherwise indicated.
@@ -91,7 +96,7 @@
 * Project: http://www.kineticjs.com, https://github.com/ericdrowell/KineticJS
 * Copyright: Eric Rowell
 
-org.objectweb.asm Version 9.0
+org.objectweb.asm Version 9.4
 * License: Modified BSD (https://asm.ow2.io/license.html)
 * Copyright (c) 2000-2011 INRIA, France Telecom. All rights reserved.
 
diff --git a/ext/bean-validation/src/main/resources/META-INF/NOTICE.markdown b/ext/bean-validation/src/main/resources/META-INF/NOTICE.markdown
index c728f22..0e566a0 100644
--- a/ext/bean-validation/src/main/resources/META-INF/NOTICE.markdown
+++ b/ext/bean-validation/src/main/resources/META-INF/NOTICE.markdown
@@ -31,7 +31,7 @@
 
 ## Third-party Content
 
-Hibernate Validator CDI, 7.0.0.Final
+Hibernate Validator CDI, 7.0.5.Final
 * License: Apache License, 2.0
 * Project: https://beanvalidation.org/
 * Repackaged in org.glassfish.jersey.server.validation.internal.hibernate
\ No newline at end of file
diff --git a/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/EntityInspectorImpl.java b/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/EntityInspectorImpl.java
index 3a69f66..b5c0943 100644
--- a/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/EntityInspectorImpl.java
+++ b/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/EntityInspectorImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2023 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
@@ -51,9 +51,7 @@
 @Singleton
 final class EntityInspectorImpl implements EntityInspector {
     private final List<EntityProcessor> entityProcessors;
-
-    @Inject
-    private EntityGraphProvider graphProvider;
+    private final EntityGraphProvider graphProvider;
 
     /**
      * Constructor expecting {@link InjectionManager} to be injected.
@@ -61,10 +59,11 @@
      * @param injectionManager injection manager to be injected.
      */
     @Inject
-    public EntityInspectorImpl(final InjectionManager injectionManager) {
+    public EntityInspectorImpl(final InjectionManager injectionManager, EntityGraphProvider graphProvider) {
         Spliterator<EntityProcessor> entities =
                 Providers.getAllProviders(injectionManager, EntityProcessor.class, new RankedComparator<>()).spliterator();
         this.entityProcessors = StreamSupport.stream(entities, false).collect(Collectors.toList());
+        this.graphProvider = graphProvider;
     }
 
     @Override
diff --git a/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/ObjectGraphProvider.java b/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/ObjectGraphProvider.java
index 5f911e3..9eb5933 100644
--- a/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/ObjectGraphProvider.java
+++ b/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/ObjectGraphProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2023 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -17,7 +17,12 @@
 package org.glassfish.jersey.message.filtering;
 
 import org.glassfish.jersey.message.filtering.spi.AbstractObjectProvider;
+import org.glassfish.jersey.message.filtering.spi.EntityGraphProvider;
+import org.glassfish.jersey.message.filtering.spi.EntityInspector;
 import org.glassfish.jersey.message.filtering.spi.ObjectGraph;
+import org.glassfish.jersey.message.filtering.spi.ScopeProvider;
+
+import jakarta.inject.Inject;
 
 /**
  * {@link org.glassfish.jersey.message.filtering.spi.ObjectProvider Object provider} and
@@ -28,6 +33,13 @@
  */
 final class ObjectGraphProvider extends AbstractObjectProvider<ObjectGraph> {
 
+    @Inject
+    public ObjectGraphProvider(ScopeProvider scopeProvider,
+                                  EntityInspector entityInspector,
+                                  EntityGraphProvider graphProvider) {
+        super(scopeProvider, entityInspector, graphProvider);
+    }
+
     @Override
     public ObjectGraph transform(final ObjectGraph graph) {
         return graph;
diff --git a/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/spi/AbstractObjectProvider.java b/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/spi/AbstractObjectProvider.java
index ac3422b..ce354db 100644
--- a/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/spi/AbstractObjectProvider.java
+++ b/ext/entity-filtering/src/main/java/org/glassfish/jersey/message/filtering/spi/AbstractObjectProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2023 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
@@ -46,15 +46,18 @@
 
     private final Cache<EntityContext, T> filteringObjects = CacheBuilder.newBuilder().maximumSize(PROVIDER_CACHE_SIZE).build();
 
-    @Inject
     private ScopeProvider scopeProvider;
-
-    @Inject
     private EntityInspector entityInspector;
-
-    @Inject
     private EntityGraphProvider graphProvider;
 
+    public AbstractObjectProvider(ScopeProvider scopeProvider,
+                                  EntityInspector entityInspector,
+                                  EntityGraphProvider graphProvider) {
+        this.scopeProvider = scopeProvider;
+        this.entityInspector = entityInspector;
+        this.graphProvider = graphProvider;
+    }
+
     @Override
     public final T getFilteringObject(final Type genericType, final boolean forWriter, final Annotation... annotations) {
         return getFilteringObject(FilteringHelper.getEntityClass(genericType), forWriter, annotations);
diff --git a/ext/metainf-services/src/test/java/org/glassfish/jersey/message/MetaInfServicesTest.java b/ext/metainf-services/src/test/java/org/glassfish/jersey/message/MetaInfServicesTest.java
index db18e3b..8458471 100644
--- a/ext/metainf-services/src/test/java/org/glassfish/jersey/message/MetaInfServicesTest.java
+++ b/ext/metainf-services/src/test/java/org/glassfish/jersey/message/MetaInfServicesTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2023 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,13 +22,13 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
 
+import jakarta.inject.Inject;
 import jakarta.ws.rs.POST;
 import jakarta.ws.rs.Path;
 import jakarta.ws.rs.WebApplicationException;
 import jakarta.ws.rs.client.Entity;
 import jakarta.ws.rs.core.Application;
 import jakarta.ws.rs.core.Configuration;
-import jakarta.ws.rs.core.Context;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.MultivaluedMap;
 import jakarta.ws.rs.core.Response;
@@ -72,7 +72,10 @@
 
     public static class MessageProvider implements MessageBodyReader<MetaInf>, MessageBodyWriter<MetaInf> {
 
-        @Context
+        @Inject
+        MessageProvider(Configuration configuration) {
+            this.config = configuration;
+        }
         private Configuration config;
 
         @Override
diff --git a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/FormParamModel.java b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/FormParamModel.java
index d38a41e..23b3ca5 100644
--- a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/FormParamModel.java
+++ b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/FormParamModel.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2023 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
@@ -45,7 +45,7 @@
                 form.param(formParamName, v.toString());
             }
         } else {
-            form.param(formParamName, resolvedValue.toString());
+            form.param(formParamName, resolvedValue == null ? null : resolvedValue.toString());
         }
         return form;
     }
diff --git a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyProxyResolverTest.java b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyProxyResolverTest.java
index 5b45ea4..9c1e9f9 100644
--- a/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyProxyResolverTest.java
+++ b/incubator/cdi-inject-weld/src/test/java/org/glassfish/jersey/inject/weld/internal/injector/JerseyProxyResolverTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2023 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
@@ -96,7 +96,7 @@
 
     @Test
     public void testProxyCreated() {
-        MyInjectionResolver injectionResolver = new MyInjectionResolver(new JaxrsProviders());
+        MyInjectionResolver injectionResolver = new MyInjectionResolver(new JaxrsProviders(null, null, null));
         InjecteeImpl injectee = new InjecteeImpl();
         injectee.setRequiredType(Providers.class);
         injectee.setParent(FIELDS[0]);
@@ -108,7 +108,7 @@
 
     @Test
     public void testProxyCached() {
-        MyInjectionResolver injectionResolver = new MyInjectionResolver(new JaxrsProviders());
+        MyInjectionResolver injectionResolver = new MyInjectionResolver(new JaxrsProviders(null, null, null));
         InjecteeImpl injectee1 = new InjecteeImpl();
         injectee1.setRequiredType(Providers.class);
         injectee1.setParent(FIELDS[0]);
@@ -125,7 +125,7 @@
 
     @Test
     public void testProxyCacheNotMismatched() {
-        MyInjectionResolver injectionResolver1 = new MyInjectionResolver(new JaxrsProviders());
+        MyInjectionResolver injectionResolver1 = new MyInjectionResolver(new JaxrsProviders(null, null, null));
         InjecteeImpl injectee1 = new InjecteeImpl();
         injectee1.setRequiredType(Providers.class);
         injectee1.setParent(FIELDS[0]);
diff --git a/incubator/injectless-client/pom.xml b/incubator/injectless-client/pom.xml
new file mode 100644
index 0000000..d1a31cf
--- /dev/null
+++ b/incubator/injectless-client/pom.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2023 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/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.glassfish.jersey.incubator</groupId>
+        <artifactId>project</artifactId>
+        <version>3.0.99-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>jersey-injectless-client</artifactId>
+    <packaging>jar</packaging>
+    <name>jersey-inject-injectless-client</name>
+
+    <description>Client side support of no injection mechanism</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <inherited>true</inherited>
+                <extensions>true</extensions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/incubator/injectless-client/src/main/java/org/glassfish/jersey/inject/injectless/NonInjectionManagerFactory.java b/incubator/injectless-client/src/main/java/org/glassfish/jersey/inject/injectless/NonInjectionManagerFactory.java
new file mode 100644
index 0000000..61e6455
--- /dev/null
+++ b/incubator/injectless-client/src/main/java/org/glassfish/jersey/inject/injectless/NonInjectionManagerFactory.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2023 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.inject.injectless;
+
+import org.glassfish.jersey.client.innate.inject.NonInjectionManager;
+import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.inject.InjectionManagerFactory;
+
+import jakarta.annotation.Priority;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.ConstrainedTo;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.RuntimeType;
+
+/**
+ * <p>
+ *     This {@link InjectionManagerFactory} implementation provides a special {@link InjectionManager}. The highest priority
+ *     of this injection manager is not to require any DI container. It is designed for pure REST client performing a request
+ *     without a further requirements for performing injections in the customer client classes, such a filter or a provider.
+ *     It means the customer classes do not have any injection points defined by {@link Inject} or {@link Context}.
+ * </p>
+ * <p>
+ *     Using this injection manager does not prevent using any Jersey modules (such as Jersey-Media-Jackson module) from working
+ *     with the client.
+ * </p>
+ */
+@Priority(15)
+@ConstrainedTo(RuntimeType.CLIENT)
+public class NonInjectionManagerFactory implements InjectionManagerFactory {
+    @Override
+    public InjectionManager create(Object parent) {
+        return new NonInjectionManager(false);
+    }
+}
diff --git a/incubator/injectless-client/src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory b/incubator/injectless-client/src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory
new file mode 100644
index 0000000..8473fa4
--- /dev/null
+++ b/incubator/injectless-client/src/main/resources/META-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory
@@ -0,0 +1 @@
+org.glassfish.jersey.inject.injectless.NonInjectionManagerFactory
\ No newline at end of file
diff --git a/incubator/kryo/src/main/java/org/glassfish/jersey/kryo/internal/KryoMessageBodyProvider.java b/incubator/kryo/src/main/java/org/glassfish/jersey/kryo/internal/KryoMessageBodyProvider.java
index afd77b1..124e7b2 100644
--- a/incubator/kryo/src/main/java/org/glassfish/jersey/kryo/internal/KryoMessageBodyProvider.java
+++ b/incubator/kryo/src/main/java/org/glassfish/jersey/kryo/internal/KryoMessageBodyProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023 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,11 +23,10 @@
 import java.lang.reflect.Type;
 import java.util.Optional;
 
+import jakarta.inject.Inject;
 import jakarta.ws.rs.Consumes;
 import jakarta.ws.rs.Produces;
 import jakarta.ws.rs.WebApplicationException;
-import jakarta.ws.rs.core.Configuration;
-import jakarta.ws.rs.core.Context;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.MultivaluedMap;
 import jakarta.ws.rs.ext.ContextResolver;
@@ -55,7 +54,8 @@
     private final ContextResolver<Kryo> contextResolver;
     private final Optional<KryoPool> kryoPool;
 
-    public KryoMessageBodyProvider(@Context Providers providers) {
+    @Inject
+    public KryoMessageBodyProvider(Providers providers) {
         final MediaType mediaType = new MediaType("application", "x-kryo");
         contextResolver = providers.getContextResolver(Kryo.class, mediaType);
         kryoPool = getKryoPool();
diff --git a/incubator/pom.xml b/incubator/pom.xml
index e82e47b..65f0a44 100644
--- a/incubator/pom.xml
+++ b/incubator/pom.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
 
-    Copyright (c) 2011, 2022 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2011, 2023 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
@@ -40,6 +40,7 @@
         <module>declarative-linking</module>
         <module>gae-integration</module>
         <module>html-json</module>
+        <module>injectless-client</module>
         <module>kryo</module>
         <module>open-tracing</module>
     </modules>
diff --git a/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/injector/JerseyProxyResolverTest.java b/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/injector/JerseyProxyResolverTest.java
index da6526d..a71e486 100644
--- a/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/injector/JerseyProxyResolverTest.java
+++ b/inject/cdi2-se/src/test/java/org/glassfish/jersey/inject/cdi/se/injector/JerseyProxyResolverTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2023 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
@@ -97,7 +97,7 @@
 
     @Test
     public void testProxyCreated() {
-        MyInjectionResolver injectionResolver = new MyInjectionResolver(new JaxrsProviders());
+        MyInjectionResolver injectionResolver = new MyInjectionResolver(new JaxrsProviders(null, null, null));
         InjecteeImpl injectee = new InjecteeImpl();
         injectee.setRequiredType(Providers.class);
         injectee.setParent(FIELDS[0]);
@@ -109,7 +109,7 @@
 
     @Test
     public void testProxyCached() {
-        MyInjectionResolver injectionResolver = new MyInjectionResolver(new JaxrsProviders());
+        MyInjectionResolver injectionResolver = new MyInjectionResolver(new JaxrsProviders(null, null, null));
         InjecteeImpl injectee1 = new InjecteeImpl();
         injectee1.setRequiredType(Providers.class);
         injectee1.setParent(FIELDS[0]);
@@ -126,7 +126,7 @@
 
     @Test
     public void testProxyCacheNotMismatched() {
-        MyInjectionResolver injectionResolver1 = new MyInjectionResolver(new JaxrsProviders());
+        MyInjectionResolver injectionResolver1 = new MyInjectionResolver(new JaxrsProviders(null, null, null));
         InjecteeImpl injectee1 = new InjecteeImpl();
         injectee1.setRequiredType(Providers.class);
         injectee1.setParent(FIELDS[0]);
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractCollectionJaxbProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractCollectionJaxbProvider.java
index 441023f..76e8750 100644
--- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractCollectionJaxbProvider.java
+++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractCollectionJaxbProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 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
@@ -39,6 +39,7 @@
 import jakarta.ws.rs.BadRequestException;
 import jakarta.ws.rs.InternalServerErrorException;
 import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.Configuration;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.MultivaluedMap;
 import jakarta.ws.rs.core.NoContentException;
@@ -120,12 +121,12 @@
         }
     };
 
-    public AbstractCollectionJaxbProvider(Providers ps) {
-        super(ps);
+    public AbstractCollectionJaxbProvider(Providers ps, Configuration config) {
+        super(ps, config);
     }
 
-    public AbstractCollectionJaxbProvider(Providers ps, MediaType mt) {
-        super(ps, mt);
+    public AbstractCollectionJaxbProvider(Providers ps, MediaType mt, Configuration config) {
+        super(ps, mt, config);
     }
 
     @Override
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractJaxbElementProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractJaxbElementProvider.java
index ec53720..63cd318 100644
--- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractJaxbElementProvider.java
+++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractJaxbElementProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 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
@@ -27,6 +27,7 @@
 import jakarta.ws.rs.BadRequestException;
 import jakarta.ws.rs.InternalServerErrorException;
 import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.Configuration;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.MultivaluedMap;
 import jakarta.ws.rs.core.NoContentException;
@@ -67,8 +68,8 @@
      *
      * @param providers JAX-RS providers.
      */
-    public AbstractJaxbElementProvider(Providers providers) {
-        super(providers);
+    public AbstractJaxbElementProvider(Providers providers, Configuration config) {
+        super(providers, config);
     }
 
     /**
@@ -77,8 +78,8 @@
      * @param providers         JAX-RS providers.
      * @param resolverMediaType JAXB component context resolver media type to be used.
      */
-    public AbstractJaxbElementProvider(Providers providers, MediaType resolverMediaType) {
-        super(providers, resolverMediaType);
+    public AbstractJaxbElementProvider(Providers providers, MediaType resolverMediaType, Configuration config) {
+        super(providers, resolverMediaType, config);
     }
 
     @Override
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractJaxbProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractJaxbProvider.java
index eac25ae..1d3c5c5 100644
--- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractJaxbProvider.java
+++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractJaxbProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 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
@@ -25,7 +25,6 @@
 import java.util.logging.Logger;
 
 import jakarta.ws.rs.core.Configuration;
-import jakarta.ws.rs.core.Context;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.ext.ContextResolver;
 import jakarta.ws.rs.ext.Providers;
@@ -71,8 +70,8 @@
      *
      * @param providers JAX-RS providers.
      */
-    public AbstractJaxbProvider(final Providers providers) {
-        this(providers, null);
+    public AbstractJaxbProvider(final Providers providers, final Configuration config) {
+        this(providers, null, config);
     }
 
     /**
@@ -81,7 +80,7 @@
      * @param providers         JAX-RS providers.
      * @param resolverMediaType JAXB component context resolver media type to be used.
      */
-    public AbstractJaxbProvider(final Providers providers, final MediaType resolverMediaType) {
+    public AbstractJaxbProvider(final Providers providers, final MediaType resolverMediaType, final Configuration config) {
         this.jaxrsProviders = providers;
 
         fixedResolverMediaType = resolverMediaType != null;
@@ -112,10 +111,10 @@
             this.mtUnmarshaller = null;
             this.mtMarshaller = null;
         }
+        setConfiguration(config);
     }
 
     // TODO This provider should be registered and configured via a feature.
-    @Context
     public void setConfiguration(final Configuration config) {
         formattedOutput = Values.lazy(new Value<Boolean>() {
 
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractRootElementJaxbProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractRootElementJaxbProvider.java
index fa12ef9..afc9dc9 100644
--- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractRootElementJaxbProvider.java
+++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/AbstractRootElementJaxbProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -26,6 +26,7 @@
 import jakarta.ws.rs.BadRequestException;
 import jakarta.ws.rs.InternalServerErrorException;
 import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.Configuration;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.MultivaluedMap;
 import jakarta.ws.rs.core.NoContentException;
@@ -69,8 +70,8 @@
      *
      * @param providers JAX-RS providers.
      */
-    public AbstractRootElementJaxbProvider(Providers providers) {
-        super(providers);
+    public AbstractRootElementJaxbProvider(Providers providers, Configuration config) {
+        super(providers, config);
     }
 
     /**
@@ -79,8 +80,8 @@
      * @param providers JAX-RS providers.
      * @param resolverMediaType JAXB component context resolver media type to be used.
      */
-    public AbstractRootElementJaxbProvider(Providers providers, MediaType resolverMediaType) {
-        super(providers, resolverMediaType);
+    public AbstractRootElementJaxbProvider(Providers providers, MediaType resolverMediaType, Configuration config) {
+        super(providers, resolverMediaType, config);
     }
 
     @Override
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/DocumentBuilderFactoryInjectionProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/DocumentBuilderFactoryInjectionProvider.java
index e327214..00bac95 100644
--- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/DocumentBuilderFactoryInjectionProvider.java
+++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/DocumentBuilderFactoryInjectionProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 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
@@ -39,11 +39,11 @@
      */
     // TODO This provider should be registered and configured via a feature.
     @Inject
-    public DocumentBuilderFactoryInjectionProvider(final Configuration config) {
+    public DocumentBuilderFactoryInjectionProvider(final InjectionManager injectionManager, final Configuration config) {
         super(config);
+        this.injectionManager = injectionManager;
     }
 
-    @Inject
     private InjectionManager injectionManager;
 
     @Override
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/DocumentProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/DocumentProvider.java
index 9a27215..4fbfcf1 100644
--- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/DocumentProvider.java
+++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/DocumentProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 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
@@ -55,10 +55,14 @@
 @Singleton
 public final class DocumentProvider extends AbstractMessageReaderWriterProvider<Document> {
 
+    private final Provider<DocumentBuilderFactory> dbf;
+    private final Provider<TransformerFactory> tf;
+
     @Inject
-    private Provider<DocumentBuilderFactory> dbf;
-    @Inject
-    private Provider<TransformerFactory> tf;
+    public DocumentProvider(Provider<DocumentBuilderFactory> dbf, Provider<TransformerFactory> tf) {
+        this.dbf = dbf;
+        this.tf = tf;
+    }
 
     @Override
     public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/SaxParserFactoryInjectionProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/SaxParserFactoryInjectionProvider.java
index 24f862a..c629439 100644
--- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/SaxParserFactoryInjectionProvider.java
+++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/SaxParserFactoryInjectionProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 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
@@ -50,11 +50,11 @@
      */
     // TODO This provider should be registered and configured via a feature.
     @Inject
-    public SaxParserFactoryInjectionProvider(final Configuration config) {
+    public SaxParserFactoryInjectionProvider(final InjectionManager injectionManager, final Configuration config) {
         super(config);
+        this.injectionManager = injectionManager;
     }
 
-    @Inject
     private InjectionManager injectionManager;
 
     @Override
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/TransformerFactoryInjectionProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/TransformerFactoryInjectionProvider.java
index a647e6e..213c4ac 100644
--- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/TransformerFactoryInjectionProvider.java
+++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/TransformerFactoryInjectionProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 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
@@ -45,11 +45,11 @@
      */
     // TODO This provider should be registered and configured via a feature.
     @Inject
-    public TransformerFactoryInjectionProvider(final Configuration config) {
+    public TransformerFactoryInjectionProvider(final InjectionManager injectionManager, final Configuration config) {
         super(config);
+        this.injectionManager = injectionManager;
     }
 
-    @Inject
     private InjectionManager injectionManager;
 
     @Override
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlCollectionJaxbProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlCollectionJaxbProvider.java
index bf26f3d..4f0af6f 100644
--- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlCollectionJaxbProvider.java
+++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlCollectionJaxbProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -24,9 +24,10 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import jakarta.inject.Inject;
 import jakarta.ws.rs.Consumes;
 import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.Configuration;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.ext.Providers;
 
@@ -50,14 +51,14 @@
 
     private final Provider<XMLInputFactory> xif;
 
-    XmlCollectionJaxbProvider(Provider<XMLInputFactory> xif, Providers ps) {
-        super(ps);
+    XmlCollectionJaxbProvider(Provider<XMLInputFactory> xif, Providers ps, Configuration config) {
+        super(ps, config);
 
         this.xif = xif;
     }
 
-    XmlCollectionJaxbProvider(Provider<XMLInputFactory> xif, Providers ps, MediaType mt) {
-        super(ps, mt);
+    XmlCollectionJaxbProvider(Provider<XMLInputFactory> xif, Providers ps, MediaType mt, Configuration config) {
+        super(ps, mt, config);
 
         this.xif = xif;
     }
@@ -71,8 +72,9 @@
     @Singleton
     public static final class App extends XmlCollectionJaxbProvider {
 
-        public App(@Context Provider<XMLInputFactory> xif, @Context Providers ps) {
-            super(xif, ps, MediaType.APPLICATION_XML_TYPE);
+        @Inject
+        public App(Provider<XMLInputFactory> xif, Providers ps, Configuration config) {
+            super(xif, ps, MediaType.APPLICATION_XML_TYPE, config);
         }
     }
 
@@ -85,8 +87,9 @@
     @Singleton
     public static final class Text extends XmlCollectionJaxbProvider {
 
-        public Text(@Context Provider<XMLInputFactory> xif, @Context Providers ps) {
-            super(xif, ps, MediaType.TEXT_XML_TYPE);
+        @Inject
+        public Text(Provider<XMLInputFactory> xif, Providers ps, Configuration config) {
+            super(xif, ps, MediaType.TEXT_XML_TYPE, config);
         }
     }
 
@@ -99,8 +102,9 @@
     @Singleton
     public static final class General extends XmlCollectionJaxbProvider {
 
-        public General(@Context Provider<XMLInputFactory> xif, @Context Providers ps) {
-            super(xif, ps);
+        @Inject
+        public General(Provider<XMLInputFactory> xif, Providers ps, Configuration config) {
+            super(xif, ps, config);
         }
 
         @Override
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlInputFactoryInjectionProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlInputFactoryInjectionProvider.java
index 99aacb3..24bb77e 100644
--- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlInputFactoryInjectionProvider.java
+++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlInputFactoryInjectionProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 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
@@ -38,11 +38,11 @@
      */
     // TODO This provider should be registered and configured via a feature.
     @Inject
-    public XmlInputFactoryInjectionProvider(final Configuration config) {
+    public XmlInputFactoryInjectionProvider(final InjectionManager injectionManager, final Configuration config) {
         super(config);
+        this.injectionManager = injectionManager;
     }
 
-    @Inject
     private InjectionManager injectionManager;
 
     @Override
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlJaxbElementProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlJaxbElementProvider.java
index 6ea3eee..10b3646 100644
--- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlJaxbElementProvider.java
+++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlJaxbElementProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 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
@@ -20,9 +20,10 @@
 import java.io.OutputStream;
 import java.nio.charset.Charset;
 
+import jakarta.inject.Inject;
 import jakarta.ws.rs.Consumes;
 import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.Configuration;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.ext.Providers;
 
@@ -44,14 +45,14 @@
 
     private final Provider<SAXParserFactory> spf;
 
-    public XmlJaxbElementProvider(Provider<SAXParserFactory> spf, Providers ps) {
-        super(ps);
+    public XmlJaxbElementProvider(Provider<SAXParserFactory> spf, Providers ps, Configuration config) {
+        super(ps, config);
 
         this.spf = spf;
     }
 
-    public XmlJaxbElementProvider(Provider<SAXParserFactory> spf, Providers ps, MediaType mt) {
-        super(ps, mt);
+    public XmlJaxbElementProvider(Provider<SAXParserFactory> spf, Providers ps, MediaType mt, Configuration config) {
+        super(ps, mt, config);
 
         this.spf = spf;
     }
@@ -65,8 +66,9 @@
     @Singleton
     public static final class App extends XmlJaxbElementProvider {
 
-        public App(@Context Provider<SAXParserFactory> spf, @Context Providers ps) {
-            super(spf, ps, MediaType.APPLICATION_XML_TYPE);
+        @Inject
+        public App(Provider<SAXParserFactory> spf, Providers ps, Configuration config) {
+            super(spf, ps, MediaType.APPLICATION_XML_TYPE, config);
         }
     }
 
@@ -79,8 +81,9 @@
     @Singleton
     public static final class Text extends XmlJaxbElementProvider {
 
-        public Text(@Context Provider<SAXParserFactory> spf, @Context Providers ps) {
-            super(spf, ps, MediaType.TEXT_XML_TYPE);
+        @Inject
+        public Text(Provider<SAXParserFactory> spf, Providers ps, Configuration config) {
+            super(spf, ps, MediaType.TEXT_XML_TYPE, config);
         }
     }
 
@@ -93,8 +96,9 @@
     @Singleton
     public static final class General extends XmlJaxbElementProvider {
 
-        public General(@Context Provider<SAXParserFactory> spf, @Context Providers ps) {
-            super(spf, ps);
+        @Inject
+        public General(Provider<SAXParserFactory> spf, Providers ps, Configuration config) {
+            super(spf, ps, config);
         }
 
         @Override
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlRootElementJaxbProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlRootElementJaxbProvider.java
index 1f08d4e..397b9ae 100644
--- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlRootElementJaxbProvider.java
+++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlRootElementJaxbProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 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,9 +18,10 @@
 
 import java.io.InputStream;
 
+import jakarta.inject.Inject;
 import jakarta.ws.rs.Consumes;
 import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.Configuration;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.ext.Providers;
 
@@ -45,14 +46,14 @@
     // Delay construction of factory
     private final Provider<SAXParserFactory> spf;
 
-    XmlRootElementJaxbProvider(Provider<SAXParserFactory> spf, Providers ps) {
-        super(ps);
+    XmlRootElementJaxbProvider(Provider<SAXParserFactory> spf, Providers ps, Configuration config) {
+        super(ps, config);
 
         this.spf = spf;
     }
 
-    XmlRootElementJaxbProvider(Provider<SAXParserFactory> spf, Providers ps, MediaType mt) {
-        super(ps, mt);
+    XmlRootElementJaxbProvider(Provider<SAXParserFactory> spf, Providers ps, MediaType mt, Configuration config) {
+        super(ps, mt, config);
 
         this.spf = spf;
     }
@@ -67,8 +68,9 @@
     @Singleton
     public static final class App extends XmlRootElementJaxbProvider {
 
-        public App(@Context Provider<SAXParserFactory> spf, @Context Providers ps) {
-            super(spf, ps, MediaType.APPLICATION_XML_TYPE);
+        @Inject
+        public App(Provider<SAXParserFactory> spf, Providers ps, Configuration config) {
+            super(spf, ps, MediaType.APPLICATION_XML_TYPE, config);
         }
     }
 
@@ -82,8 +84,9 @@
     @Singleton
     public static final class Text extends XmlRootElementJaxbProvider {
 
-        public Text(@Context Provider<SAXParserFactory> spf, @Context Providers ps) {
-            super(spf, ps, MediaType.TEXT_XML_TYPE);
+        @Inject
+        public Text(Provider<SAXParserFactory> spf, Providers ps, Configuration config) {
+            super(spf, ps, MediaType.TEXT_XML_TYPE, config);
         }
     }
 
@@ -97,8 +100,9 @@
     @Singleton
     public static final class General extends XmlRootElementJaxbProvider {
 
-        public General(@Context Provider<SAXParserFactory> spf, @Context Providers ps) {
-            super(spf, ps);
+        @Inject
+        public General(Provider<SAXParserFactory> spf, Providers ps, Configuration config) {
+            super(spf, ps, config);
         }
 
         @Override
diff --git a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlRootObjectJaxbProvider.java b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlRootObjectJaxbProvider.java
index 9a8593c..76e61a1 100644
--- a/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlRootObjectJaxbProvider.java
+++ b/media/jaxb/src/main/java/org/glassfish/jersey/jaxb/internal/XmlRootObjectJaxbProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 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,12 +22,13 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
 
+import jakarta.inject.Inject;
 import jakarta.ws.rs.BadRequestException;
 import jakarta.ws.rs.Consumes;
 import jakarta.ws.rs.InternalServerErrorException;
 import jakarta.ws.rs.Produces;
 import jakarta.ws.rs.WebApplicationException;
-import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.Configuration;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.MultivaluedMap;
 import jakarta.ws.rs.core.NoContentException;
@@ -53,14 +54,14 @@
 
     private final Provider<SAXParserFactory> spf;
 
-    XmlRootObjectJaxbProvider(Provider<SAXParserFactory> spf, Providers ps) {
-        super(ps);
+    XmlRootObjectJaxbProvider(Provider<SAXParserFactory> spf, Providers ps, Configuration config) {
+        super(ps, config);
 
         this.spf = spf;
     }
 
-    XmlRootObjectJaxbProvider(Provider<SAXParserFactory> spf, Providers ps, MediaType mt) {
-        super(ps, mt);
+    XmlRootObjectJaxbProvider(Provider<SAXParserFactory> spf, Providers ps, MediaType mt, Configuration config) {
+        super(ps, mt, config);
 
         this.spf = spf;
     }
@@ -79,8 +80,9 @@
     @Singleton
     public static final class App extends XmlRootObjectJaxbProvider {
 
-        public App(@Context Provider<SAXParserFactory> spf, @Context Providers ps) {
-            super(spf, ps, MediaType.APPLICATION_XML_TYPE);
+        @Inject
+        public App(Provider<SAXParserFactory> spf, Providers ps, Configuration config) {
+            super(spf, ps, MediaType.APPLICATION_XML_TYPE, config);
         }
     }
 
@@ -93,8 +95,9 @@
     @Singleton
     public static final class Text extends XmlRootObjectJaxbProvider {
 
-        public Text(@Context Provider<SAXParserFactory> spf, @Context Providers ps) {
-            super(spf, ps, MediaType.TEXT_XML_TYPE);
+        @Inject
+        public Text(Provider<SAXParserFactory> spf, Providers ps, Configuration config) {
+            super(spf, ps, MediaType.TEXT_XML_TYPE, config);
         }
     }
 
@@ -107,8 +110,9 @@
     @Singleton
     public static final class General extends XmlRootObjectJaxbProvider {
 
-        public General(@Context Provider<SAXParserFactory> spf, @Context Providers ps) {
-            super(spf, ps);
+        @Inject
+        public General(Provider<SAXParserFactory> spf, Providers ps, Configuration config) {
+            super(spf, ps, config);
         }
 
         @Override
diff --git a/media/jaxb/src/test/java/org/glassfish/jersey/jaxb/internal/JaxbStringReaderProviderTest.java b/media/jaxb/src/test/java/org/glassfish/jersey/jaxb/internal/JaxbStringReaderProviderTest.java
index a0b4c26..2285de0 100644
--- a/media/jaxb/src/test/java/org/glassfish/jersey/jaxb/internal/JaxbStringReaderProviderTest.java
+++ b/media/jaxb/src/test/java/org/glassfish/jersey/jaxb/internal/JaxbStringReaderProviderTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 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
@@ -48,7 +48,7 @@
     public void stringReaderDoesNotReadExternalDtds() {
 
         Provider<SAXParserFactory> saxParserFactoryProvider = new Provider<SAXParserFactory>() {
-            final SaxParserFactoryInjectionProvider spf = new SaxParserFactoryInjectionProvider(
+            final SaxParserFactoryInjectionProvider spf = new SaxParserFactoryInjectionProvider(null,
                     new CommonConfig(RuntimeType.SERVER, ComponentBag.INCLUDE_ALL));
 
             @Override
diff --git a/media/json-binding/src/main/java/org/glassfish/jersey/jsonb/internal/JsonBindingProvider.java b/media/json-binding/src/main/java/org/glassfish/jersey/jsonb/internal/JsonBindingProvider.java
index efc7c81..c2ffe9e 100644
--- a/media/json-binding/src/main/java/org/glassfish/jersey/jsonb/internal/JsonBindingProvider.java
+++ b/media/json-binding/src/main/java/org/glassfish/jersey/jsonb/internal/JsonBindingProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2023 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,10 +23,15 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
 
+import jakarta.json.bind.Jsonb;
+import jakarta.json.bind.JsonbBuilder;
+import jakarta.json.bind.JsonbException;
+
 import org.glassfish.jersey.jsonb.LocalizationMessages;
 import org.glassfish.jersey.message.internal.AbstractMessageReaderWriterProvider;
 import org.glassfish.jersey.message.internal.EntityInputStream;
 
+import jakarta.inject.Inject;
 import jakarta.json.bind.Jsonb;
 import jakarta.json.bind.JsonbBuilder;
 import jakarta.json.bind.JsonbException;
@@ -34,7 +39,6 @@
 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;
@@ -55,9 +59,10 @@
     private static final String JSON = "json";
     private static final String PLUS_JSON = "+json";
 
-    private Providers providers;
+    private final Providers providers;
 
-    public JsonBindingProvider(@Context Providers providers) {
+    @Inject
+    public JsonBindingProvider(Providers providers) {
         this.providers = providers;
     }
 
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
index a35dfad..ec86d03 100644
--- 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2023 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,11 +23,11 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
 
+import jakarta.inject.Inject;
 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;
@@ -56,7 +56,8 @@
 
     private Providers providers;
 
-    public JsonGsonProvider(@Context Providers providers) {
+    @Inject
+    public JsonGsonProvider(Providers providers) {
         this.providers = providers;
     }
 
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java
index 527f1db..9abfbf1 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2023 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
@@ -25,19 +25,25 @@
 import java.util.Arrays;
 import java.util.List;
 import jakarta.annotation.PostConstruct;
+import jakarta.inject.Inject;
 import jakarta.inject.Singleton;
 import jakarta.ws.rs.core.Configuration;
-import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.ext.Providers;
 
 /**
  * Entity Data provider based on Jackson JSON provider.
  */
 @Singleton
 public class DefaultJacksonJaxbJsonProvider extends JacksonJaxbJsonProvider {
-
-    @Context
     private Configuration commonConfig;
 
+    @Inject
+    public DefaultJacksonJaxbJsonProvider(Providers providers, Configuration config) {
+        super(new JacksonMapperConfigurator(null, DEFAULT_ANNOTATIONS));
+        this.commonConfig = config;
+        _providers = providers;
+    }
+
     //do not register JaxbAnnotationModule because it brakes default annotations processing
     private static final String[] EXCLUDE_MODULE_NAMES = {"JaxbAnnotationModule", "JakartaXmlBindAnnotationModule"};
 
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/FilteringJacksonJaxbJsonProvider.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/FilteringJacksonJaxbJsonProvider.java
index 815b45e..486ec09 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/FilteringJacksonJaxbJsonProvider.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/FilteringJacksonJaxbJsonProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023 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,12 +22,14 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Type;
 
+import jakarta.ws.rs.core.Configuration;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.MultivaluedMap;
 
 import jakarta.inject.Inject;
 import jakarta.inject.Provider;
 import jakarta.inject.Singleton;
+import jakarta.ws.rs.ext.Providers;
 
 import org.glassfish.jersey.internal.util.ReflectionHelper;
 import org.glassfish.jersey.jackson.internal.jackson.jaxrs.cfg.EndpointConfigBase;
@@ -57,8 +59,15 @@
 @Singleton
 public final class FilteringJacksonJaxbJsonProvider extends DefaultJacksonJaxbJsonProvider {
 
+    private final Provider<ObjectProvider<FilterProvider>> provider;
+
     @Inject
-    private Provider<ObjectProvider<FilterProvider>> provider;
+    public FilteringJacksonJaxbJsonProvider(Provider<ObjectProvider<FilterProvider>> provider,
+                                            Providers providers, Configuration config) {
+        super(providers, config);
+        this.provider = provider;
+    }
+
 
     @Override
     protected JsonEndpointConfig _configForWriting(final ObjectMapper mapper, final Annotation[] annotations,
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/JacksonObjectProvider.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/JacksonObjectProvider.java
index d341486..b4b37f4 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/JacksonObjectProvider.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/JacksonObjectProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023 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,8 @@
 import java.util.Stack;
 
 import org.glassfish.jersey.message.filtering.spi.AbstractObjectProvider;
+import org.glassfish.jersey.message.filtering.spi.EntityGraphProvider;
+import org.glassfish.jersey.message.filtering.spi.EntityInspector;
 import org.glassfish.jersey.message.filtering.spi.ObjectGraph;
 
 import com.fasterxml.jackson.core.JsonGenerator;
@@ -35,12 +37,22 @@
 import com.fasterxml.jackson.databind.ser.PropertyFilter;
 import com.fasterxml.jackson.databind.ser.PropertyWriter;
 import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
+import org.glassfish.jersey.message.filtering.spi.ScopeProvider;
+
+import jakarta.inject.Inject;
 
 /**
  * @author Michal Gajdos
  */
 final class JacksonObjectProvider extends AbstractObjectProvider<FilterProvider> {
 
+    @Inject
+    public JacksonObjectProvider(ScopeProvider scopeProvider,
+                                  EntityInspector entityInspector,
+                                  EntityGraphProvider graphProvider) {
+        super(scopeProvider, entityInspector, graphProvider);
+    }
+
     @Override
     public FilterProvider transform(final ObjectGraph graph) {
         // Root entity.
diff --git a/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForDisabledModulesTest.java b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForDisabledModulesTest.java
index dc68332..9b7beb9 100644
--- a/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForDisabledModulesTest.java
+++ b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForDisabledModulesTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2023 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
@@ -55,6 +55,9 @@
     private static class TestJacksonJaxbJsonProvider extends JacksonJaxbJsonProvider {
 
         @Inject
+        public TestJacksonJaxbJsonProvider(Configuration configuration) {
+            this.configuration = configuration;
+        }
         private Configuration configuration;
 
         @PostConstruct
diff --git a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonJaxbElementProvider.java b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonJaxbElementProvider.java
index 51ec8ad..e8c3ac6 100644
--- a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonJaxbElementProvider.java
+++ b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonJaxbElementProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -24,9 +24,10 @@
 import java.lang.reflect.Type;
 import java.nio.charset.Charset;
 
+import jakarta.inject.Inject;
 import jakarta.ws.rs.Consumes;
 import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.Configuration;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.ext.Providers;
 
@@ -47,12 +48,12 @@
  */
 public class JettisonJaxbElementProvider extends AbstractJaxbElementProvider {
 
-    JettisonJaxbElementProvider(Providers ps) {
-        super(ps);
+    JettisonJaxbElementProvider(Providers ps, Configuration config) {
+        super(ps, config);
     }
 
-    JettisonJaxbElementProvider(Providers ps, MediaType mt) {
-        super(ps, mt);
+    JettisonJaxbElementProvider(Providers ps, MediaType mt, Configuration config) {
+        super(ps, mt, config);
     }
 
     @Override
@@ -69,8 +70,9 @@
     @Consumes("application/json")
     public static final class App extends JettisonJaxbElementProvider {
 
-        public App(@Context Providers ps) {
-            super(ps, MediaType.APPLICATION_JSON_TYPE);
+        @Inject
+        public App(Providers ps, Configuration config) {
+            super(ps, MediaType.APPLICATION_JSON_TYPE, config);
         }
     }
 
@@ -78,8 +80,9 @@
     @Consumes("*/*")
     public static final class General extends JettisonJaxbElementProvider {
 
-        public General(@Context Providers ps) {
-            super(ps);
+        @Inject
+        public General(Providers ps, Configuration config) {
+            super(ps, config);
         }
 
         @Override
diff --git a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonListElementProvider.java b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonListElementProvider.java
index 8f6395b..61380c1 100644
--- a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonListElementProvider.java
+++ b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonListElementProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 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
@@ -28,9 +28,10 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import jakarta.inject.Inject;
 import jakarta.ws.rs.Consumes;
 import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.Configuration;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.ext.Providers;
 
@@ -54,12 +55,12 @@
  */
 public class JettisonListElementProvider extends AbstractCollectionJaxbProvider {
 
-    JettisonListElementProvider(Providers ps) {
-        super(ps);
+    JettisonListElementProvider(Providers ps, Configuration config) {
+        super(ps, config);
     }
 
-    JettisonListElementProvider(Providers ps, MediaType mt) {
-        super(ps, mt);
+    JettisonListElementProvider(Providers ps, MediaType mt, Configuration config) {
+        super(ps, mt, config);
     }
 
     @Override
@@ -75,9 +76,9 @@
     @Produces("application/json")
     @Consumes("application/json")
     public static final class App extends JettisonListElementProvider {
-
-        public App(@Context Providers ps) {
-            super(ps, MediaType.APPLICATION_JSON_TYPE);
+        @Inject
+        public App(Providers ps, Configuration config) {
+            super(ps, MediaType.APPLICATION_JSON_TYPE, config);
         }
     }
 
@@ -85,8 +86,9 @@
     @Consumes("*/*")
     public static final class General extends JettisonListElementProvider {
 
-        public General(@Context Providers ps) {
-            super(ps);
+        @Inject
+        public General(Providers ps, Configuration config) {
+            super(ps, config);
         }
 
         @Override
diff --git a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonRootElementProvider.java b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonRootElementProvider.java
index 71e4810..b43ea1d 100644
--- a/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonRootElementProvider.java
+++ b/media/json-jettison/src/main/java/org/glassfish/jersey/jettison/internal/entity/JettisonRootElementProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -24,9 +24,10 @@
 import java.lang.reflect.Type;
 import java.nio.charset.Charset;
 
+import jakarta.inject.Inject;
 import jakarta.ws.rs.Consumes;
 import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.Configuration;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.ext.Providers;
 
@@ -48,12 +49,12 @@
  */
 public class JettisonRootElementProvider extends AbstractRootElementJaxbProvider {
 
-    JettisonRootElementProvider(Providers ps) {
-        super(ps);
+    JettisonRootElementProvider(Providers ps, Configuration config) {
+        super(ps, config);
     }
 
-    JettisonRootElementProvider(Providers ps, MediaType mt) {
-        super(ps, mt);
+    JettisonRootElementProvider(Providers ps, MediaType mt, Configuration config) {
+        super(ps, mt, config);
     }
 
     @Override
@@ -69,18 +70,18 @@
     @Produces("application/json")
     @Consumes("application/json")
     public static final class App extends JettisonRootElementProvider {
-
-        public App(@Context Providers ps) {
-            super(ps, MediaType.APPLICATION_JSON_TYPE);
+        @Inject
+        public App(Providers ps, Configuration config) {
+            super(ps, MediaType.APPLICATION_JSON_TYPE, config);
         }
     }
 
     @Produces("*/*")
     @Consumes("*/*")
     public static final class General extends JettisonRootElementProvider {
-
-        public General(@Context Providers ps) {
-            super(ps);
+        @Inject
+        public General(Providers ps, Configuration config) {
+            super(ps, config);
         }
 
         @Override
diff --git a/media/moxy/src/main/java/org/glassfish/jersey/moxy/internal/MoxyObjectProvider.java b/media/moxy/src/main/java/org/glassfish/jersey/moxy/internal/MoxyObjectProvider.java
index a5d4b7d..0e33d25 100644
--- a/media/moxy/src/main/java/org/glassfish/jersey/moxy/internal/MoxyObjectProvider.java
+++ b/media/moxy/src/main/java/org/glassfish/jersey/moxy/internal/MoxyObjectProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2023 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
@@ -20,9 +20,12 @@
 import java.util.Map;
 import java.util.Set;
 
+import jakarta.inject.Inject;
 import jakarta.xml.bind.JAXBException;
 
 import org.glassfish.jersey.message.filtering.spi.AbstractObjectProvider;
+import org.glassfish.jersey.message.filtering.spi.EntityGraphProvider;
+import org.glassfish.jersey.message.filtering.spi.EntityInspector;
 import org.glassfish.jersey.message.filtering.spi.ObjectGraph;
 
 import org.eclipse.persistence.jaxb.JAXBContext;
@@ -30,6 +33,7 @@
 import org.eclipse.persistence.jaxb.JAXBHelper;
 import org.eclipse.persistence.jaxb.Subgraph;
 import org.eclipse.persistence.jaxb.TypeMappingInfo;
+import org.glassfish.jersey.message.filtering.spi.ScopeProvider;
 
 /**
  * @author Michal Gajdos
@@ -47,6 +51,13 @@
         }
     }
 
+    @Inject
+    public MoxyObjectProvider(ScopeProvider scopeProvider,
+                              EntityInspector entityInspector,
+                              EntityGraphProvider graphProvider) {
+        super(scopeProvider, entityInspector, graphProvider);
+    }
+
     @Override
     public org.eclipse.persistence.jaxb.ObjectGraph transform(final ObjectGraph graph) {
         return createObjectGraph(graph.getEntityClass(), graph);
diff --git a/media/moxy/src/main/java/org/glassfish/jersey/moxy/json/internal/ConfigurableMoxyJsonProvider.java b/media/moxy/src/main/java/org/glassfish/jersey/moxy/json/internal/ConfigurableMoxyJsonProvider.java
index b7f3f09..6d07e04 100644
--- a/media/moxy/src/main/java/org/glassfish/jersey/moxy/json/internal/ConfigurableMoxyJsonProvider.java
+++ b/media/moxy/src/main/java/org/glassfish/jersey/moxy/json/internal/ConfigurableMoxyJsonProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2023 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -26,9 +26,9 @@
 import java.util.Map;
 import java.util.Set;
 
+import jakarta.inject.Inject;
 import jakarta.inject.Singleton;
 import jakarta.ws.rs.core.Configuration;
-import jakarta.ws.rs.core.Context;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.MultivaluedMap;
 import jakarta.ws.rs.ext.ContextResolver;
@@ -77,11 +77,13 @@
         return propertyNames;
     }
 
-    @Context
-    private Providers providers;
+    private final Configuration config;
 
-    @Context
-    private Configuration config;
+    @Inject
+    public ConfigurableMoxyJsonProvider(Providers providers, Configuration config) {
+        this.providers = providers;
+        this.config = config;
+    }
 
     private MoxyJsonConfig globalConfig;
 
diff --git a/media/moxy/src/main/java/org/glassfish/jersey/moxy/json/internal/FilteringMoxyJsonProvider.java b/media/moxy/src/main/java/org/glassfish/jersey/moxy/json/internal/FilteringMoxyJsonProvider.java
index ac0a0a8..2a0ef42 100644
--- a/media/moxy/src/main/java/org/glassfish/jersey/moxy/json/internal/FilteringMoxyJsonProvider.java
+++ b/media/moxy/src/main/java/org/glassfish/jersey/moxy/json/internal/FilteringMoxyJsonProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2023 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,12 +19,14 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
 
+import jakarta.ws.rs.core.Configuration;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.MultivaluedMap;
 
 import jakarta.inject.Inject;
 import jakarta.inject.Provider;
 import jakarta.inject.Singleton;
+import jakarta.ws.rs.ext.Providers;
 import jakarta.xml.bind.JAXBException;
 import jakarta.xml.bind.Marshaller;
 import jakarta.xml.bind.Unmarshaller;
@@ -41,9 +43,15 @@
  */
 @Singleton
 public class FilteringMoxyJsonProvider extends ConfigurableMoxyJsonProvider {
+    private final Provider<ObjectProvider<ObjectGraph>> provider;
 
     @Inject
-    private Provider<ObjectProvider<ObjectGraph>> provider;
+    public FilteringMoxyJsonProvider(Provider<ObjectProvider<ObjectGraph>> provider,
+                                     Providers providers,
+                                     Configuration config) {
+        super(providers, config);
+        this.provider = provider;
+    }
 
     @Override
     protected void preWriteTo(final Object object, final Class<?> type, final Type genericType, final Annotation[] annotations,
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderClientSide.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderClientSide.java
index 6d1f0f4..d8d4762 100644
--- a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderClientSide.java
+++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderClientSide.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 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,7 +32,6 @@
 import jakarta.ws.rs.Consumes;
 import jakarta.ws.rs.RuntimeType;
 import jakarta.ws.rs.WebApplicationException;
-import jakarta.ws.rs.core.Context;
 import jakarta.ws.rs.core.HttpHeaders;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.MultivaluedMap;
@@ -77,16 +76,15 @@
      * Injectable helper to look up appropriate {@link MessageBodyReader}s
      * for our body parts.
      */
-    @Inject
     private Provider<MessageBodyWorkers> messageBodyWorkers;
-
     private final MIMEConfig mimeConfig;
 
     /**
      * Accepts constructor injection of the configuration parameters for this
      * application.
      */
-    public MultiPartReaderClientSide(@Context final Providers providers) {
+    @Inject
+    public MultiPartReaderClientSide(final Providers providers, Provider<MessageBodyWorkers> messageBodyWorkers) {
         final ContextResolver<MultiPartProperties> contextResolver =
                 providers.getContextResolver(MultiPartProperties.class, MediaType.WILDCARD_TYPE);
 
@@ -98,6 +96,7 @@
             properties = new MultiPartProperties();
         }
 
+        this.messageBodyWorkers = messageBodyWorkers;
         mimeConfig = createMimeConfig(properties);
     }
 
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderServerSide.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderServerSide.java
index 0662c04..59c4c58 100644
--- a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderServerSide.java
+++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartReaderServerSide.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 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,7 +23,6 @@
 
 import jakarta.ws.rs.ConstrainedTo;
 import jakarta.ws.rs.RuntimeType;
-import jakarta.ws.rs.core.Context;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.MultivaluedMap;
 import jakarta.ws.rs.ext.MessageBodyReader;
@@ -34,6 +33,7 @@
 import jakarta.inject.Singleton;
 
 import org.glassfish.jersey.media.multipart.MultiPart;
+import org.glassfish.jersey.message.MessageBodyWorkers;
 import org.glassfish.jersey.server.CloseableService;
 
 import org.jvnet.mimepull.MIMEParsingException;
@@ -52,9 +52,10 @@
     private final Provider<CloseableService> closeableServiceProvider;
 
     @Inject
-    public MultiPartReaderServerSide(@Context final Providers providers,
-                                     final Provider<CloseableService> closeableServiceProvider) {
-        super(providers);
+    public MultiPartReaderServerSide(final Providers providers,
+                                     final Provider<CloseableService> closeableServiceProvider,
+                                     final Provider<MessageBodyWorkers> messageBodyWorkers) {
+        super(providers, messageBodyWorkers);
         this.closeableServiceProvider = closeableServiceProvider;
     }
 
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartWriter.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartWriter.java
index 4e155f8..5237d7e 100644
--- a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartWriter.java
+++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/internal/MultiPartWriter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 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
@@ -27,9 +27,9 @@
 import java.util.List;
 import java.util.Map;
 
+import jakarta.inject.Inject;
 import jakarta.ws.rs.Produces;
 import jakarta.ws.rs.WebApplicationException;
-import jakarta.ws.rs.core.Context;
 import jakarta.ws.rs.core.HttpHeaders;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.MultivaluedMap;
@@ -64,7 +64,8 @@
      */
     private final Providers providers;
 
-    public MultiPartWriter(@Context final Providers providers) {
+    @Inject
+    public MultiPartWriter(final Providers providers) {
         this.providers = providers;
     }
 
diff --git a/media/sse/src/main/java/org/glassfish/jersey/media/sse/EventInputReader.java b/media/sse/src/main/java/org/glassfish/jersey/media/sse/EventInputReader.java
index cf5db6a..91ea8ba 100644
--- a/media/sse/src/main/java/org/glassfish/jersey/media/sse/EventInputReader.java
+++ b/media/sse/src/main/java/org/glassfish/jersey/media/sse/EventInputReader.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 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
@@ -31,7 +31,6 @@
 
 import org.glassfish.jersey.internal.PropertiesDelegate;
 import org.glassfish.jersey.message.MessageBodyWorkers;
-import org.glassfish.jersey.message.MessageUtils;
 import org.glassfish.jersey.message.internal.ReaderInterceptorExecutor;
 
 /**
@@ -41,10 +40,14 @@
  */
 class EventInputReader implements MessageBodyReader<EventInput> {
 
+    private final Provider<MessageBodyWorkers> messageBodyWorkers;
+    private final Provider<PropertiesDelegate> propertiesDelegateProvider;
+
     @Inject
-    private Provider<MessageBodyWorkers> messageBodyWorkers;
-    @Inject
-    private Provider<PropertiesDelegate> propertiesDelegateProvider;
+    EventInputReader(Provider<MessageBodyWorkers> messageBodyWorkers, Provider<PropertiesDelegate> propertiesDelegateProvider) {
+        this.messageBodyWorkers = messageBodyWorkers;
+        this.propertiesDelegateProvider = propertiesDelegateProvider;
+    }
 
     @Override
     public boolean isReadable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
diff --git a/media/sse/src/main/java/org/glassfish/jersey/media/sse/InboundEventReader.java b/media/sse/src/main/java/org/glassfish/jersey/media/sse/InboundEventReader.java
index d4401f6..93eb446 100644
--- a/media/sse/src/main/java/org/glassfish/jersey/media/sse/InboundEventReader.java
+++ b/media/sse/src/main/java/org/glassfish/jersey/media/sse/InboundEventReader.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 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
@@ -49,8 +49,12 @@
     private static final Logger LOGGER = Logger.getLogger(InboundEventReader.class.getName());
     private static final byte[] EOL_DATA = new byte[] {'\n'};
 
+    private final Provider<MessageBodyWorkers> messageBodyWorkers;
+
     @Inject
-    private Provider<MessageBodyWorkers> messageBodyWorkers;
+    InboundEventReader(Provider<MessageBodyWorkers> messageBodyWorkers) {
+        this.messageBodyWorkers = messageBodyWorkers;
+    }
 
     private enum State {
         SKIPPING_PREPENDED_EMPTY_EVENTS,
diff --git a/media/sse/src/main/java/org/glassfish/jersey/media/sse/OutboundEventWriter.java b/media/sse/src/main/java/org/glassfish/jersey/media/sse/OutboundEventWriter.java
index b0ba040..18d9546 100644
--- a/media/sse/src/main/java/org/glassfish/jersey/media/sse/OutboundEventWriter.java
+++ b/media/sse/src/main/java/org/glassfish/jersey/media/sse/OutboundEventWriter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 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
@@ -52,8 +52,12 @@
     private static final byte[] DATA_LEAD = "data: ".getBytes(UTF8);
     private static final byte[] EOL = {'\n'};
 
+    private final Provider<MessageBodyWorkers> workersProvider;
+
     @Inject
-    private Provider<MessageBodyWorkers> workersProvider;
+    public OutboundEventWriter(Provider<MessageBodyWorkers> workersProvider) {
+        this.workersProvider = workersProvider;
+    }
 
     @Override
     public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations,
diff --git a/pom.xml b/pom.xml
index 10b3e20..399326e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -428,6 +428,12 @@
                                 junit.jupiter.execution.parallel.mode.default=same_thread
                             </configurationParameters>
                         </properties>
+                        <systemProperties>
+                            <property>
+                                <name>jersey.config.test.container.port</name>
+                                <value>${jersey.config.test.container.port}</value>
+                            </property>
+                        </systemProperties>
                         <threadCount>124</threadCount>
                     </configuration>
                     <dependencies>
@@ -629,6 +635,12 @@
                         <skipTests>${skip.tests}</skipTests>
                         <skipITs>${skip.tests}</skipITs>
                         <argLine>${failsafe.coverage.argline}</argLine>
+                        <systemProperties>
+                            <property>
+                                <name>jersey.config.test.container.port</name>
+                                <value>${jersey.config.test.container.port}</value>
+                            </property>
+                        </systemProperties>
                     </configuration>
                     <executions>
                         <execution>
@@ -853,6 +865,26 @@
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-resources-plugin</artifactId>
             </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <version>${buildhelper.mvn.plugin.version}</version>
+                <configuration>
+                    <portNames>
+                        <portName>jersey.config.test.container.port</portName>
+                        <portName>jersey.config.test.container.stop.port</portName>
+                    </portNames>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>reserve-port</id>
+                        <phase>process-test-classes</phase> <!-- pre-integration-test -->
+                        <goals>
+                            <goal>reserve-network-port</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
         <extensions>
             <extension>
@@ -1450,7 +1482,7 @@
                     <doctitle>Jersey ${jersey.version} API Documentation</doctitle>
                     <windowtitle>Jersey ${jersey.version} API</windowtitle>
                     <bottom>
-                        <![CDATA[Copyright &#169; 2007-2022,
+                        <![CDATA[Copyright &#169; 2007-2023,
                             <a href="http://www.oracle.com">Oracle</a>
                             and/or its affiliates.
                             All Rights Reserved. Use is subject to license terms.]]>
@@ -2221,8 +2253,8 @@
         <xmlunit.version>2.9.0</xmlunit.version>
         <hk2.osgi.version>org.glassfish.hk2.*;version="[2.5,4)"</hk2.osgi.version>
         <hk2.jvnet.osgi.version>org.jvnet.hk2.*;version="[2.5,4)"</hk2.jvnet.osgi.version>
-        <httpclient.version>4.5.13</httpclient.version>
-        <httpclient5.version>5.1.3</httpclient5.version>
+        <httpclient.version>4.5.14</httpclient.version>
+        <httpclient5.version>5.2.1</httpclient5.version>
         <jackson.version>2.14.1</jackson.version>
         <javassist.version>3.29.0-GA</javassist.version>
         <jboss.logging.version>3.4.2.Final</jboss.logging.version>
diff --git a/security/oauth1-client/src/main/java/org/glassfish/jersey/client/oauth1/OAuth1ClientFilter.java b/security/oauth1-client/src/main/java/org/glassfish/jersey/client/oauth1/OAuth1ClientFilter.java
index eab1cb1..b3d466a 100644
--- a/security/oauth1-client/src/main/java/org/glassfish/jersey/client/oauth1/OAuth1ClientFilter.java
+++ b/security/oauth1-client/src/main/java/org/glassfish/jersey/client/oauth1/OAuth1ClientFilter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2023 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
@@ -48,11 +48,14 @@
 @Priority(Priorities.AUTHENTICATION)
 class OAuth1ClientFilter implements ClientRequestFilter {
 
-    @Inject
     private Provider<OAuth1Signature> oAuthSignature;
+    private Provider<MessageBodyWorkers> messageBodyWorkers;
 
     @Inject
-    private Provider<MessageBodyWorkers> messageBodyWorkers;
+    public OAuth1ClientFilter(Provider<OAuth1Signature> oAuthSignature, Provider<MessageBodyWorkers> messageBodyWorkers) {
+        this.oAuthSignature = oAuthSignature;
+        this.messageBodyWorkers = messageBodyWorkers;
+    }
 
     @Override
     public void filter(ClientRequestContext request) throws IOException {
diff --git a/security/oauth2-client/src/main/java/org/glassfish/jersey/client/oauth2/AuthCodeGrantImpl.java b/security/oauth2-client/src/main/java/org/glassfish/jersey/client/oauth2/AuthCodeGrantImpl.java
index bed3cee..6a54ce1 100644
--- a/security/oauth2-client/src/main/java/org/glassfish/jersey/client/oauth2/AuthCodeGrantImpl.java
+++ b/security/oauth2-client/src/main/java/org/glassfish/jersey/client/oauth2/AuthCodeGrantImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2023 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
@@ -354,11 +354,15 @@
     static class DefaultTokenMessageBodyReader implements MessageBodyReader<TokenResult> {
 
         // Provider here prevents circular dependency error from HK2 (workers inject providers and this provider inject workers)
-        @Inject
-        private Provider<MessageBodyWorkers> workers;
+        private final Provider<MessageBodyWorkers> workers;
+        private final Provider<PropertiesDelegate> propertiesDelegateProvider;
 
         @Inject
-        private Provider<PropertiesDelegate> propertiesDelegateProvider;
+        public DefaultTokenMessageBodyReader(Provider<MessageBodyWorkers> workers,
+                                             Provider<PropertiesDelegate> propertiesDelegateProvider) {
+            this.propertiesDelegateProvider = propertiesDelegateProvider;
+            this.workers = workers;
+        }
 
         private static Iterable<ReaderInterceptor> EMPTY_INTERCEPTORS = new ArrayList<>();
 
diff --git a/tests/e2e-client/pom.xml b/tests/e2e-client/pom.xml
index 8dae6fa..35dd31c 100644
--- a/tests/e2e-client/pom.xml
+++ b/tests/e2e-client/pom.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
 
-    Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2017, 2023 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
@@ -46,6 +46,25 @@
                         <sun.net.http.allowRestrictedHeaders>true</sun.net.http.allowRestrictedHeaders>
                     </systemPropertyVariables>
                 </configuration>
+                <executions>
+                    <execution>
+                        <id>WithHK2</id>
+                        <goals>
+                            <goal>test</goal>
+                        </goals>
+                        <configuration>
+                            <excludes>
+                                <exclude>**/NonInjectionManagerTest.java</exclude>
+                            </excludes>
+                            <systemPropertyVariables>
+                                <jersey.injectionmanager.hk2>true</jersey.injectionmanager.hk2>
+                            </systemPropertyVariables>
+                            <classpathDependencyExcludes>
+                                <classpathDependencyExclude>org.glassfish.jersey.incubator:jersey-injectless-client</classpathDependencyExclude>
+                            </classpathDependencyExcludes>
+                        </configuration>
+                    </execution>
+                </executions>
             </plugin>
         </plugins>
     </build>
@@ -161,6 +180,12 @@
             <version>${project.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.incubator</groupId>
+            <artifactId>jersey-injectless-client</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
 
         <dependency>
             <groupId>org.glassfish.jersey.test-framework</groupId>
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/HttpHeadersInjectionTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/HttpHeadersInjectionTest.java
index a0d90fb..a1a6418 100644
--- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/HttpHeadersInjectionTest.java
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/HttpHeadersInjectionTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2023 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
@@ -20,6 +20,7 @@
 import org.glassfish.jersey.test.JerseyTest;
 import org.junit.jupiter.api.Test;
 
+import jakarta.inject.Inject;
 import jakarta.ws.rs.Consumes;
 import jakarta.ws.rs.POST;
 import jakarta.ws.rs.Path;
@@ -43,7 +44,6 @@
 import jakarta.ws.rs.ext.WriterInterceptor;
 import jakarta.ws.rs.ext.WriterInterceptorContext;
 import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -74,10 +74,13 @@
     }
 
     public static class HttpHeadersFilter implements ClientRequestFilter {
-
-        @Context
         HttpHeaders headers;
 
+        @Inject
+        public HttpHeadersFilter(HttpHeaders headers) {
+            this.headers = headers;
+        }
+
         @Override
         public void filter(ClientRequestContext requestContext) throws IOException {
             requestContext.abortWith(Response.ok(headers.getHeaderString(HEADER_NAME)).build());
@@ -85,10 +88,13 @@
     }
 
     public static class HttpHeadersResponseFilter implements ClientResponseFilter {
-
-        @Context
         HttpHeaders headers;
 
+        @Inject
+        public HttpHeadersResponseFilter(HttpHeaders headers) {
+            this.headers = headers;
+        }
+
         private static int headerValue = 0;
 
         public int getHeaderValue() {
@@ -103,9 +109,13 @@
 
     @Produces(MediaType.TEXT_PLAIN)
     public static class StringWriter implements MessageBodyWriter<String> {
-        @Context
         HttpHeaders headers;
 
+        @Inject
+        public StringWriter(HttpHeaders headers) {
+            this.headers = headers;
+        }
+
         @Override
         public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
             return true;
@@ -122,10 +132,13 @@
 
     @Consumes({MediaType.TEXT_PLAIN})
     public static class StringReader implements MessageBodyReader<String> {
-
-        @Context
         HttpHeaders headers;
 
+        @Inject
+        public StringReader(HttpHeaders headers) {
+            this.headers = headers;
+        }
+
         @Override
         public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
             return true;
@@ -140,10 +153,13 @@
     }
 
     public static class HttpHeadersReaderInterceptor implements ReaderInterceptor {
-
-        @Context
         HttpHeaders headers;
 
+        @Inject
+        public HttpHeadersReaderInterceptor(HttpHeaders headers) {
+            this.headers = headers;
+        }
+
         @Override
         public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException {
             context.getInputStream().close();
@@ -153,10 +169,13 @@
     }
 
     public static class HttpHeadersWriterInterceptor implements WriterInterceptor {
-
-        @Context
         HttpHeaders headers;
 
+        @Inject
+        public HttpHeadersWriterInterceptor(HttpHeaders headers) {
+            this.headers = headers;
+        }
+
         @Override
         public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
             OutputStreamWriter osw = new OutputStreamWriter(context.getOutputStream());
@@ -177,7 +196,7 @@
     @Test
     public void testHttpHeadersInjectionInResponseFilter() {
         final String value = "1";
-        final HttpHeadersResponseFilter filter = new HttpHeadersResponseFilter();
+        final HttpHeadersResponseFilter filter = new HttpHeadersResponseFilter(null);
         final String response = target().register(HttpHeadersResponseFilter.class).request().header(HEADER_NAME, value)
                 .buildPost(Entity.entity(value, MediaType.TEXT_PLAIN_TYPE)).invoke(String.class);
         assertThat(response, is(value));
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/InjectedClientBodyWorker.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/InjectedClientBodyWorker.java
index 7cf59c2..e42453b 100644
--- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/InjectedClientBodyWorker.java
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/InjectedClientBodyWorker.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2023 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.lang.annotation.Annotation;
 import java.lang.reflect.Type;
 
+import jakarta.inject.Inject;
 import jakarta.ws.rs.Consumes;
 import jakarta.ws.rs.POST;
 import jakarta.ws.rs.Path;
@@ -30,7 +31,6 @@
 import jakarta.ws.rs.client.Entity;
 import jakarta.ws.rs.core.Application;
 import jakarta.ws.rs.core.Configuration;
-import jakarta.ws.rs.core.Context;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.MultivaluedMap;
 import jakarta.ws.rs.ext.ContextResolver;
@@ -73,10 +73,13 @@
     @Provider
     @Produces(ProviderType)
     public static class ProvidersInjectedWriter implements MessageBodyWriter<String> {
-
-        @Context
         Providers providers;
 
+        @Inject
+        public ProvidersInjectedWriter(Providers providers) {
+            this.providers = providers;
+        }
+
         @Override
         public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
             return type == String.class;
@@ -105,9 +108,13 @@
     @Consumes(ProviderType)
     public static class ProvidersInjectedReader implements MessageBodyReader<String> {
 
-        @Context
         Providers providers;
 
+        @Inject
+        ProvidersInjectedReader(Providers providers) {
+            this.providers = providers;
+        }
+
         @Override
         public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
             return type == String.class;
@@ -132,9 +139,13 @@
     @Produces(ConfigurationTYPE)
     public static class ConfigurationInjectedWriter implements MessageBodyWriter<String> {
 
-        @Context
         Configuration configuration;
 
+        @Inject
+        public ConfigurationInjectedWriter(Configuration configuration) {
+            this.configuration = configuration;
+        }
+
         @Override
         public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
             return type == String.class;
@@ -158,10 +169,13 @@
     @Provider
     @Consumes(ConfigurationTYPE)
     public static class ConfigurationInjectedReader implements MessageBodyReader<String> {
-
-        @Context
         Configuration configuration;
 
+        @Inject
+        public ConfigurationInjectedReader(Configuration configuration) {
+            this.configuration = configuration;
+        }
+
         @Override
         public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
             return type == String.class;
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/NonInjectionManagerTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/NonInjectionManagerTest.java
new file mode 100644
index 0000000..d547792
--- /dev/null
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/NonInjectionManagerTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2023 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.client;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.ClientRequestFilter;
+import jakarta.ws.rs.core.Response;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+import org.glassfish.jersey.inject.injectless.NonInjectionManagerFactory;
+
+public class NonInjectionManagerTest {
+    @Test
+    public void testNonInjectionManagerIsUsed() {
+        String value = System.getProperty("jersey.injectionmanager.hk2");
+        if ("true".equals(value)) {
+            return;
+        }
+
+        Records records = new Records();
+        Logger logger = Logger.getLogger(new NonInjectionManagerFactory().create(null).getClass().getName());
+        Level oldLevel = logger.getLevel();
+        logger.setLevel(Level.FINEST);
+        logger.addHandler(records);
+
+        ClientBuilder.newClient().register((ClientRequestFilter) requestContext -> {
+            requestContext.abortWith(Response.ok().build());
+        }).target("http://localhost:9998/nevermind").request().get();
+
+        logger.removeHandler(records);
+        logger.setLevel(oldLevel);
+
+        LogRecord warning = records.records.get(0);
+        Assertions.assertTrue(warning.getMessage().contains("injection-less"));
+    }
+
+    private static class Records extends Handler {
+        private List<LogRecord> records = new LinkedList<>();
+        @Override
+        public void publish(LogRecord record) {
+            records.add(record);
+        }
+
+        @Override
+        public void flush() {
+        }
+
+        @Override
+        public void close() throws SecurityException {
+        }
+    }
+}
diff --git a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/RequestScopedReadEntityTest.java b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/RequestScopedReadEntityTest.java
index d53685e..78ce436 100644
--- a/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/RequestScopedReadEntityTest.java
+++ b/tests/e2e-client/src/test/java/org/glassfish/jersey/tests/e2e/client/RequestScopedReadEntityTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 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
@@ -71,9 +71,12 @@
 
     @Produces("text/plain")
     public static class ScopedMessageEntityProvider extends AbstractMessageReaderWriterProvider<Message> {
+        private final Provider<ClientRequest> clientRequestProvider;
 
         @Inject
-        private Provider<ClientRequest> clientRequestProvider;
+        public ScopedMessageEntityProvider(Provider<ClientRequest> clientRequestProvider) {
+            this.clientRequestProvider = clientRequestProvider;
+        }
 
         @Override
         public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
diff --git a/tests/e2e-entity/pom.xml b/tests/e2e-entity/pom.xml
index 7e0c7db..06324ed 100644
--- a/tests/e2e-entity/pom.xml
+++ b/tests/e2e-entity/pom.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
 
-    Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2017, 2023 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
@@ -43,6 +43,19 @@
                     <enableAssertions>false</enableAssertions>
                     <skipTests>${skip.e2e}</skipTests>
                 </configuration>
+                <executions>
+                    <execution>
+                        <id>WithHK2</id>
+                        <goals>
+                            <goal>test</goal>
+                        </goals>
+                        <configuration>
+                            <classpathDependencyExcludes>
+                                <classpathDependencyExclude>org.glassfish.jersey.incubator:jersey-injectless-client</classpathDependencyExclude>
+                            </classpathDependencyExcludes>
+                        </configuration>
+                    </execution>
+                </executions>
             </plugin>
         </plugins>
     </build>
@@ -171,6 +184,13 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>org.glassfish.jersey.incubator</groupId>
+            <artifactId>jersey-injectless-client</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
             <groupId>org.hamcrest</groupId>
             <artifactId>hamcrest</artifactId>
             <scope>test</scope>
diff --git a/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/filtering/FilteringMessageBodyProvider.java b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/filtering/FilteringMessageBodyProvider.java
index fe6c3df..b76f67a 100644
--- a/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/filtering/FilteringMessageBodyProvider.java
+++ b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/filtering/FilteringMessageBodyProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2023 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
@@ -52,8 +52,12 @@
 
     private static final Logger LOGGER = Logger.getLogger(FilteringMessageBodyProvider.class.getName());
 
+    private final jakarta.inject.Provider<ObjectProvider<ObjectGraph>> provider;
+
     @Inject
-    private jakarta.inject.Provider<ObjectProvider<ObjectGraph>> provider;
+    public FilteringMessageBodyProvider(jakarta.inject.Provider<ObjectProvider<ObjectGraph>> provider) {
+        this.provider = provider;
+    }
 
     @Override
     public boolean isReadable(final Class<?> type, final Type genericType, final Annotation[] annotations,
diff --git a/tests/e2e-server/pom.xml b/tests/e2e-server/pom.xml
index a3760af..57873f4 100644
--- a/tests/e2e-server/pom.xml
+++ b/tests/e2e-server/pom.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
 
-    Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2017, 2023 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
@@ -43,6 +43,19 @@
                     <enableAssertions>false</enableAssertions>
                     <skipTests>${skip.e2e}</skipTests>
                 </configuration>
+                <executions>
+                    <execution>
+                        <id>WithHK2</id>
+                        <goals>
+                            <goal>test</goal>
+                        </goals>
+                        <configuration>
+                            <classpathDependencyExcludes>
+                                <classpathDependencyExclude>org.glassfish.jersey.incubator:jersey-injectless-client</classpathDependencyExclude>
+                            </classpathDependencyExcludes>
+                        </configuration>
+                    </execution>
+                </executions>
             </plugin>
         </plugins>
     </build>
@@ -179,6 +192,13 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>org.glassfish.jersey.incubator</groupId>
+            <artifactId>jersey-injectless-client</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
             <groupId>org.glassfish.jersey.test-framework</groupId>
             <artifactId>jersey-test-framework-util</artifactId>
             <scope>test</scope>
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ManagedClientExecutorTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ManagedClientExecutorTest.java
index 43d18e0..b771c54 100644
--- a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ManagedClientExecutorTest.java
+++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ManagedClientExecutorTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2023 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
@@ -33,6 +33,7 @@
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.logging.LogRecord;
 
 import jakarta.ws.rs.GET;
 import jakarta.ws.rs.Path;
@@ -63,6 +64,11 @@
  */
 public class ManagedClientExecutorTest extends JerseyTest {
 
+    public ManagedClientExecutorTest() {
+        // The tests need to run on port 9998, since @Uri() annotation needs a constant String with a port
+        System.setProperty(TestProperties.CONTAINER_PORT, "9998");
+    }
+
     @Override
     protected ResourceConfig configure() {
         enable(TestProperties.LOG_TRAFFIC);
@@ -213,11 +219,15 @@
      */
     public static class SchedulerThreadNameReader implements MessageBodyReader<SchedulerThreadName> {
 
-        @Inject
-        ScheduledExecutorServiceProvider injectedProvider;
+        private final ScheduledExecutorServiceProvider injectedProvider;
+        private final ScheduledExecutorService injectedService;
 
         @Inject
-        ScheduledExecutorService injectedService;
+        public SchedulerThreadNameReader(ScheduledExecutorService injectedService,
+                                         ScheduledExecutorServiceProvider injectedProvider) {
+            this.injectedProvider = injectedProvider;
+            this.injectedService = injectedService;
+        }
 
         @Override
         public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
@@ -256,8 +266,15 @@
 
     @Test
     public void testManagedClientExecutor() {
-        final String response = target().path("test/executor").request().get(String.class);
-        Assertions.assertEquals("foo-executor-service-0", response);
+        try {
+            final String response = target().path("test/executor").request().get(String.class);
+            Assertions.assertEquals("foo-executor-service-0", response);
+        } catch (Exception e) {
+            for (LogRecord record : getLoggedRecords()) {
+                System.out.println(record.getMessage());
+            }
+        }
+
     }
 
     @Test
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/validation/validateonexecution/ValidateOnExecutionOverrideTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/validation/validateonexecution/ValidateOnExecutionOverrideTest.java
index e2830bd..8aa3801 100644
--- a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/validation/validateonexecution/ValidateOnExecutionOverrideTest.java
+++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/validation/validateonexecution/ValidateOnExecutionOverrideTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2023 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,6 +19,7 @@
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.LogRecord;
+import java.util.stream.Collectors;
 
 import jakarta.ws.rs.GET;
 import jakarta.ws.rs.Path;
@@ -101,8 +102,13 @@
     private void _test(final String path) throws Exception {
         assertThat(target(path).request().get().getStatus(), equalTo(500));
 
-        final List<LogRecord> loggedRecords = getLoggedRecords();
+        final List<LogRecord> loggedRecords = getLoggedRecords()
+                .stream()
+                .filter(log -> log.getSourceClassName().equals(LOGGER_NAME)) // Skip warnings from outside of Validation
+                .collect(Collectors.toList());
         assertThat(loggedRecords.size(), equalTo(1));
         assertThat(loggedRecords.get(0).getThrown(), instanceOf(ValidationException.class));
     }
+
+    private static final String LOGGER_NAME = "org.glassfish.jersey.server.validation.internal.ValidationExceptionMapper";
 }
diff --git a/tests/e2e-tls/pom.xml b/tests/e2e-tls/pom.xml
new file mode 100644
index 0000000..1ae746c
--- /dev/null
+++ b/tests/e2e-tls/pom.xml
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2023 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.tests</groupId>
+        <artifactId>project</artifactId>
+        <version>3.0.99-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>e2e-tls</artifactId>
+    <name>jersey-tests-e2e-tls</name>
+    <packaging>jar</packaging>
+
+    <description>Jersey E2E SSL/TLS tests</description>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <forkCount>1</forkCount>
+                    <reuseForks>false</reuseForks>
+                    <enableAssertions>false</enableAssertions>
+                    <skipTests>${skip.e2e}</skipTests>
+                    <systemPropertyVariables>
+                        <sun.net.http.allowRestrictedHeaders>true</sun.net.http.allowRestrictedHeaders>
+                        <property>
+                            <name>ssl.debug</name>
+                            <value>true</value>
+                        </property>
+                    </systemPropertyVariables>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+            <artifactId>jersey-test-framework-provider-bundle</artifactId>
+            <type>pom</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework</groupId>
+            <artifactId>jersey-test-framework-util</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.platform</groupId>
+            <artifactId>junit-platform-suite</artifactId>
+            <version>${junit-platform-suite.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.specto</groupId>
+            <artifactId>hoverfly-java-junit5</artifactId>
+            <version>0.14.0</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.glassfish.jersey.connectors</groupId>
+            <artifactId>jersey-apache-connector</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.connectors</groupId>
+            <artifactId>jersey-apache5-connector</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.connectors</groupId>
+            <artifactId>jersey-grizzly-connector</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.connectors</groupId>
+            <artifactId>jersey-jetty-connector</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.connectors</groupId>
+            <artifactId>jersey-jdk-connector</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.security</groupId>
+            <artifactId>oauth1-signature</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <profiles>
+        <profile>
+            <id>jdk11+</id>
+            <activation>
+                <jdk>[11,)</jdk>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>com.sun.xml.bind</groupId>
+                    <artifactId>jaxb-osgi</artifactId>
+                    <scope>test</scope>
+                </dependency>
+            </dependencies>
+            <properties>
+                <!-- https://bugs.openjdk.java.net/browse/JDK-8211426 -->
+                <surefire.security.argline>-Djdk.tls.server.protocols=TLSv1.2</surefire.security.argline>
+            </properties>
+        </profile>
+    </profiles>
+
+</project>
diff --git a/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/ClientHelloTestServer.java b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/ClientHelloTestServer.java
new file mode 100644
index 0000000..703d1c8
--- /dev/null
+++ b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/ClientHelloTestServer.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2023 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.tls;
+
+import org.glassfish.jersey.tests.e2e.tls.explorer.SSLCapabilities;
+import org.glassfish.jersey.tests.e2e.tls.explorer.SSLExplorer;
+
+import javax.net.ServerSocketFactory;
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SNIMatcher;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+public class ClientHelloTestServer {
+    private ServerSocket serverSocket;
+    private Thread serverThread;
+    private volatile State state = State.NONE;
+
+    private enum State {
+        NONE,
+        INIT,
+        STARTED,
+        STOPPED
+    }
+
+    protected ServerSocketFactory getServerSocketFactory() {
+        return ServerSocketFactory.getDefault();
+    }
+
+    protected void afterHandshake(Socket socket, SSLCapabilities capabilities) {
+
+    }
+
+    public void init(int port) {
+        ServerSocketFactory factory = getServerSocketFactory();
+        try {
+            serverSocket = factory.createServerSocket(port);
+
+            state = State.INIT;
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void start() {
+        if (state != State.INIT) {
+            System.out.println("Server has not been initialized");
+        }
+        Thread thread = new Thread(() -> {
+            while (state == State.INIT) {
+                Socket socket = null;
+                try {
+                    socket = serverSocket.accept();
+
+                    inspect(socket);
+                } catch (SocketException e) {
+                    if (!e.getMessage().equals("Interrupted function call: accept failed")) {
+                        e.printStackTrace();
+                    }
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        });
+        serverThread = thread;
+        thread.start();
+    }
+
+    public void stop() {
+        try {
+            state = State.STOPPED;
+            serverSocket.close();
+            serverThread.join();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void inspect(Socket socket) throws IOException {
+        InputStream ins = socket.getInputStream();
+
+        byte[] buffer = new byte[0xFF];
+        int position = 0;
+        SSLCapabilities capabilities = null;
+
+// Read the header of TLS record
+        while (position < SSLExplorer.RECORD_HEADER_SIZE) {
+            int count = SSLExplorer.RECORD_HEADER_SIZE - position;
+            int n = ins.read(buffer, position, count);
+            if (n < 0) {
+                throw new IOException("unexpected end of stream!");
+            }
+            position += n;
+        }
+
+// Get the required size to explore the SSL capabilities
+        int recordLength = SSLExplorer.getRequiredSize(buffer, 0, position);
+        if (buffer.length < recordLength) {
+            buffer = Arrays.copyOf(buffer, recordLength);
+        }
+
+        while (position < recordLength) {
+            int count = recordLength - position;
+            int n = ins.read(buffer, position, count);
+            if (n < 0) {
+                throw new IOException("unexpected end of stream!");
+            }
+            position += n;
+        }
+
+// Explore
+        capabilities = SSLExplorer.explore(buffer, 0, recordLength);
+        if (capabilities != null) {
+            System.out.println("Record version: " + capabilities.getRecordVersion());
+            System.out.println("Hello version: " + capabilities.getHelloVersion());
+        }
+
+        afterHandshake(socket, capabilities);
+    }
+}
diff --git a/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/SniTest.java b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/SniTest.java
new file mode 100644
index 0000000..1e8d893
--- /dev/null
+++ b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/SniTest.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2023 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.tls;
+
+import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
+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.jdk.connector.JdkConnectorProvider;
+import org.glassfish.jersey.netty.connector.NettyConnectorProvider;
+import org.glassfish.jersey.tests.e2e.tls.explorer.SSLCapabilities;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import javax.net.ssl.SNIServerName;
+import jakarta.ws.rs.client.ClientBuilder;
+import jakarta.ws.rs.client.ClientRequestContext;
+import jakarta.ws.rs.client.ClientRequestFilter;
+import jakarta.ws.rs.core.HttpHeaders;
+import jakarta.ws.rs.core.Response;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import java.net.URI;
+import java.net.UnknownHostException;
+import java.nio.charset.StandardCharsets;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public class SniTest {
+    private static final int PORT = 8443;
+    private static final String LOCALHOST = "127.0.0.1";
+
+
+    static {
+        // JDK specific settings
+        System.setProperty("jdk.net.hosts.file", SniTest.class.getResource("/hosts").getPath());
+    }
+
+    public static ConnectorProvider[] getConnectors() {
+        return new ConnectorProvider[] {
+                new NettyConnectorProvider(),
+                new ApacheConnectorProvider(),
+                new Apache5ConnectorProvider(),
+                new JdkConnectorProvider(),
+                new HttpUrlConnectorProvider()
+        };
+    }
+
+    @ParameterizedTest
+    @MethodSource("getConnectors")
+    public void server1Test(ConnectorProvider provider) {
+        ClientConfig clientConfig = new ClientConfig();
+        clientConfig.connectorProvider(provider);
+        serverTest(clientConfig, "www.host1.com");
+    }
+
+    public void serverTest(ClientConfig clientConfig, String hostName) {
+        String newHostName = replaceWhenHostNotKnown(hostName);
+        final List<SNIServerName> serverNames = new LinkedList<>();
+        final String[] requestHostName = new String[1];
+        ClientHelloTestServer server = new ClientHelloTestServer() {
+            @Override
+            protected void afterHandshake(Socket socket, SSLCapabilities capabilities) {
+                serverNames.addAll(capabilities.getServerNames());
+            }
+        };
+        server.init(PORT);
+        server.start();
+
+        clientConfig.property(ClientProperties.READ_TIMEOUT, 2000);
+        clientConfig.property(ClientProperties.CONNECT_TIMEOUT, 2000);
+        try (Response r = ClientBuilder.newClient(clientConfig)
+                .register(new ClientRequestFilter() {
+                    @Override
+                    public void filter(ClientRequestContext requestContext) throws IOException {
+                        requestHostName[0] = requestContext.getUri().getHost();
+                    }
+                })
+                .target("https://" + (newHostName.equals(LOCALHOST) ? LOCALHOST : "www.host0.com") + ":" + PORT)
+                .path("host")
+                .request()
+                .header(HttpHeaders.HOST, hostName + ":8080")
+                .get()) {
+            // empty
+        } catch (Exception e) {
+            Throwable cause = e;
+            while (cause != null
+                    && !SocketTimeoutException.class.isInstance(cause)
+                    && TimeoutException.class.isInstance(cause)) {
+                cause = cause.getCause();
+            }
+            if (cause == null && /*IOE*/ !e.getMessage().contains("Stream closed")) {
+                throw e;
+            }
+        }
+
+        server.stop();
+
+        if (serverNames.isEmpty()) {
+            throw new IllegalStateException("ServerNames are empty");
+        }
+
+        String clientSniName = new String(serverNames.get(0).getEncoded());
+        if (!hostName.equals(clientSniName)) {
+            throw new IllegalStateException("Unexpected client SNI name " + clientSniName);
+        }
+
+        if (!LOCALHOST.equals(newHostName) && requestHostName[0].equals(hostName)) {
+            throw new IllegalStateException("The HTTP Request is made with the same");
+        }
+
+        System.out.append("Found expected Client SNI ").println(serverNames.get(0));
+    }
+
+    /*
+     * The method checks whether the JDK-dependent property "jdk.net.hosts.file" works.
+     * If it does, the request is made with the hostname, so that the 3rd party client has
+     * the request with the hostname. If a real address is returned or UnknownHostException
+     * is thrown, the property did not work and the request needs to use 127.0.0.1.
+     */
+    private static String replaceWhenHostNotKnown(String hostName) {
+        try {
+            InetAddress inetAddress = InetAddress.getByName(hostName);
+            return LOCALHOST.equals(inetAddress.getHostAddress()) ? hostName : LOCALHOST;
+        } catch (UnknownHostException e) {
+            return LOCALHOST;
+        }
+    }
+}
diff --git a/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/explorer/SSLCapabilities.java b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/explorer/SSLCapabilities.java
new file mode 100644
index 0000000..e21b86a
--- /dev/null
+++ b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/explorer/SSLCapabilities.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2013, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle or the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.glassfish.jersey.tests.e2e.tls.explorer;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+import javax.net.ssl.SNIServerName;
+
+/**
+ * Encapsulates the security capabilities of an SSL/TLS connection.
+ * <P>
+ * The security capabilities are the list of ciphersuites to be accepted in
+ * an SSL/TLS handshake, the record version, the hello version, and server
+ * name indication, etc., of an SSL/TLS connection.
+ * <P>
+ * <code>SSLCapabilities</code> can be retrieved by exploring the network
+ * data of an SSL/TLS connection via {@link SSLExplorer#explore(ByteBuffer)}
+ * or {@link SSLExplorer#explore(byte[], int, int)}.
+ *
+ * @see SSLExplorer
+ */
+public abstract class SSLCapabilities {
+
+    /**
+     * Returns the record version of an SSL/TLS connection
+     *
+     * @return a non-null record version
+     */
+    public abstract String getRecordVersion();
+
+    /**
+     * Returns the hello version of an SSL/TLS connection
+     *
+     * @return a non-null hello version
+     */
+    public abstract String getHelloVersion();
+
+    /**
+     * Returns a <code>List</code> containing all {@link SNIServerName}s
+     * of the server name indication.
+     *
+     * @return a non-null immutable list of {@link SNIServerName}s
+     *         of the server name indication parameter, may be empty
+     *         if no server name indication.
+     *
+     * @see SNIServerName
+     */
+    public abstract List<SNIServerName> getServerNames();
+}
+
diff --git a/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/explorer/SSLExplorer.java b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/explorer/SSLExplorer.java
new file mode 100644
index 0000000..71c1f4e
--- /dev/null
+++ b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/explorer/SSLExplorer.java
@@ -0,0 +1,627 @@
+package org.glassfish.jersey.tests.e2e.tls.explorer;
+
+/*
+ * Copyright (c) 2013, 2023 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle or the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SNIServerName;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLProtocolException;
+import javax.net.ssl.StandardConstants;
+import java.nio.ByteBuffer;
+import java.nio.BufferUnderflowException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Instances of this class acts as an explorer of the network data of an
+ * SSL/TLS connection.
+ */
+public final class SSLExplorer {
+
+    // Private constructor prevents construction outside this class.
+    private SSLExplorer() {
+    }
+
+    /**
+     * The header size of TLS/SSL records.
+     * <P>
+     * The value of this constant is {@value}.
+     */
+    public static final int RECORD_HEADER_SIZE = 0x05;
+
+    /**
+     * Returns the required number of bytes in the {@code source}
+     * {@link ByteBuffer} necessary to explore SSL/TLS connection.
+     * <P>
+     * This method tries to parse as few bytes as possible from
+     * {@code source} byte buffer to get the length of an
+     * SSL/TLS record.
+     * <P>
+     * This method accesses the {@code source} parameter in read-only
+     * mode, and does not update the buffer's properties such as capacity,
+     * limit, position, and mark values.
+     *
+     * @param  source
+     *         a {@link ByteBuffer} containing
+     *         inbound or outbound network data for an SSL/TLS connection.
+     * @throws BufferUnderflowException if less than {@code RECORD_HEADER_SIZE}
+     *         bytes remaining in {@code source}
+     * @return the required size in byte to explore an SSL/TLS connection
+     */
+    public static int getRequiredSize(ByteBuffer source) {
+
+        ByteBuffer input = source.duplicate();
+
+        // Do we have a complete header?
+        if (input.remaining() < RECORD_HEADER_SIZE) {
+            throw new BufferUnderflowException();
+        }
+
+        // Is it a handshake message?
+        byte firstByte = input.get();
+        byte secondByte = input.get();
+        byte thirdByte = input.get();
+        if ((firstByte & 0x80) != 0 && thirdByte == 0x01) {
+            // looks like a V2ClientHello
+            // return (((firstByte & 0x7F) << 8) | (secondByte & 0xFF)) + 2;
+            return RECORD_HEADER_SIZE;   // Only need the header fields
+        } else {
+            return (((input.get() & 0xFF) << 8) | (input.get() & 0xFF)) + 5;
+        }
+    }
+
+    /**
+     * Returns the required number of bytes in the {@code source} byte array
+     * necessary to explore SSL/TLS connection.
+     * <P>
+     * This method tries to parse as few bytes as possible from
+     * {@code source} byte array to get the length of an
+     * SSL/TLS record.
+     *
+     * @param  source
+     *         a byte array containing inbound or outbound network data for
+     *         an SSL/TLS connection.
+     * @param  offset
+     *         the start offset in array {@code source} at which the
+     *         network data is read from.
+     * @param  length
+     *         the maximum number of bytes to read.
+     *
+     * @throws BufferUnderflowException if less than {@code RECORD_HEADER_SIZE}
+     *         bytes remaining in {@code source}
+     * @return the required size in byte to explore an SSL/TLS connection
+     */
+    public static int getRequiredSize(byte[] source,
+                                            int offset, int length) throws IOException {
+
+        ByteBuffer byteBuffer =
+                ByteBuffer.wrap(source, offset, length).asReadOnlyBuffer();
+        return getRequiredSize(byteBuffer);
+    }
+
+    /**
+     * Launch and explore the security capabilities from byte buffer.
+     * <P>
+     * This method tries to parse as few records as possible from
+     * {@code source} byte buffer to get the {@link SSLCapabilities}
+     * of an SSL/TLS connection.
+     * <P>
+     * Please NOTE that this method must be called before any handshaking
+     * occurs.  The behavior of this method is not defined in this release
+     * if the handshake has begun, or has completed.
+     * <P>
+     * This method accesses the {@code source} parameter in read-only
+     * mode, and does not update the buffer's properties such as capacity,
+     * limit, position, and mark values.
+     *
+     * @param  source
+     *         a {@link ByteBuffer} containing
+     *         inbound or outbound network data for an SSL/TLS connection.
+     *
+     * @throws IOException on network data error
+     * @throws BufferUnderflowException if not enough source bytes available
+     *         to make a complete exploration.
+     *
+     * @return the explored {@link SSLCapabilities} of the SSL/TLS
+     *         connection
+     */
+    public static SSLCapabilities explore(ByteBuffer source)
+            throws IOException {
+
+        ByteBuffer input = source.duplicate();
+
+        // Do we have a complete header?
+        if (input.remaining() < RECORD_HEADER_SIZE) {
+            throw new BufferUnderflowException();
+        }
+
+        // Is it a handshake message?
+        byte firstByte = input.get();
+        byte secondByte = input.get();
+        byte thirdByte = input.get();
+        if ((firstByte & 0x80) != 0 && thirdByte == 0x01) {
+            // looks like a V2ClientHello
+            return exploreV2HelloRecord(input,
+                    firstByte, secondByte, thirdByte);
+        } else if (firstByte == 22) {   // 22: handshake record
+            return exploreTLSRecord(input,
+                    firstByte, secondByte, thirdByte);
+        } else {
+            throw new SSLException("Not handshake record");
+        }
+    }
+
+    /**
+     * Launch and explore the security capabilities from byte array.
+     * <P>
+     * Please NOTE that this method must be called before any handshaking
+     * occurs.  The behavior of this method is not defined in this release
+     * if the handshake has begun, or has completed.  Once handshake has
+     * begun, or has completed, the security capabilities can not and
+     * should not be launched with this method.
+     *
+     * @param  source
+     *         a byte array containing inbound or outbound network data for
+     *         an SSL/TLS connection.
+     * @param  offset
+     *         the start offset in array {@code source} at which the
+     *         network data is read from.
+     * @param  length
+     *         the maximum number of bytes to read.
+     *
+     * @throws IOException on network data error
+     * @throws BufferUnderflowException if not enough source bytes available
+     *         to make a complete exploration.
+     * @return the explored {@link SSLCapabilities} of the SSL/TLS
+     *         connection
+     *
+     * @see #explore(ByteBuffer)
+     */
+    public static SSLCapabilities explore(byte[] source,
+                                                int offset, int length) throws IOException {
+        ByteBuffer byteBuffer =
+                ByteBuffer.wrap(source, offset, length).asReadOnlyBuffer();
+        return explore(byteBuffer);
+    }
+
+    /*
+     * uint8 V2CipherSpec[3];
+     * struct {
+     *     uint16 msg_length;         // The highest bit MUST be 1;
+     *                                // the remaining bits contain the length
+     *                                // of the following data in bytes.
+     *     uint8 msg_type;            // MUST be 1
+     *     Version version;
+     *     uint16 cipher_spec_length; // It cannot be zero and MUST be a
+     *                                // multiple of the V2CipherSpec length.
+     *     uint16 session_id_length;  // This field MUST be empty.
+     *     uint16 challenge_length;   // SHOULD use a 32-byte challenge
+     *     V2CipherSpec cipher_specs[V2ClientHello.cipher_spec_length];
+     *     opaque session_id[V2ClientHello.session_id_length];
+     *     opaque challenge[V2ClientHello.challenge_length;
+     * } V2ClientHello;
+     */
+    private static SSLCapabilities exploreV2HelloRecord(
+            ByteBuffer input, byte firstByte, byte secondByte,
+            byte thirdByte) throws IOException {
+
+        // We only need the header. We have already had enough source bytes.
+        // int recordLength = (firstByte & 0x7F) << 8) | (secondByte & 0xFF);
+        try {
+            // Is it a V2ClientHello?
+            if (thirdByte != 0x01) {
+                throw new SSLException(
+                        "Unsupported or Unrecognized SSL record");
+            }
+
+            // What's the hello version?
+            byte helloVersionMajor = input.get();
+            byte helloVersionMinor = input.get();
+
+            // 0x00: major version of SSLv20
+            // 0x02: minor version of SSLv20
+            //
+            // SNIServerName is an extension, SSLv20 doesn't support extension.
+            return new SSLCapabilitiesImpl((byte) 0x00, (byte) 0x02,
+                    helloVersionMajor, helloVersionMinor,
+                    Collections.<SNIServerName>emptyList());
+        } catch (BufferUnderflowException bufe) {
+            throw new SSLProtocolException(
+                    "Invalid handshake record");
+        }
+    }
+
+    /*
+     * struct {
+     *     uint8 major;
+     *     uint8 minor;
+     * } ProtocolVersion;
+     *
+     * enum {
+     *     change_cipher_spec(20), alert(21), handshake(22),
+     *     application_data(23), (255)
+     * } ContentType;
+     *
+     * struct {
+     *     ContentType type;
+     *     ProtocolVersion version;
+     *     uint16 length;
+     *     opaque fragment[TLSPlaintext.length];
+     * } TLSPlaintext;
+     */
+    private static SSLCapabilities exploreTLSRecord(
+            ByteBuffer input, byte firstByte, byte secondByte,
+            byte thirdByte) throws IOException {
+
+        // Is it a handshake message?
+        if (firstByte != 22) {        // 22: handshake record
+            throw new SSLException("Not handshake record");
+        }
+
+        // We need the record version to construct SSLCapabilities.
+        byte recordMajorVersion = secondByte;
+        byte recordMinorVersion = thirdByte;
+
+        // Is there enough data for a full record?
+        int recordLength = getInt16(input);
+        if (recordLength > input.remaining()) {
+            throw new BufferUnderflowException();
+        }
+
+        // We have already had enough source bytes.
+        try {
+            return exploreHandshake(input,
+                    recordMajorVersion, recordMinorVersion, recordLength);
+        } catch (BufferUnderflowException bufe) {
+            throw new SSLProtocolException(
+                    "Invalid handshake record");
+        }
+    }
+
+    /*
+     * enum {
+     *     hello_request(0), client_hello(1), server_hello(2),
+     *     certificate(11), server_key_exchange (12),
+     *     certificate_request(13), server_hello_done(14),
+     *     certificate_verify(15), client_key_exchange(16),
+     *     finished(20)
+     *     (255)
+     * } HandshakeType;
+     *
+     * struct {
+     *     HandshakeType msg_type;
+     *     uint24 length;
+     *     select (HandshakeType) {
+     *         case hello_request:       HelloRequest;
+     *         case client_hello:        ClientHello;
+     *         case server_hello:        ServerHello;
+     *         case certificate:         Certificate;
+     *         case server_key_exchange: ServerKeyExchange;
+     *         case certificate_request: CertificateRequest;
+     *         case server_hello_done:   ServerHelloDone;
+     *         case certificate_verify:  CertificateVerify;
+     *         case client_key_exchange: ClientKeyExchange;
+     *         case finished:            Finished;
+     *     } body;
+     * } Handshake;
+     */
+    private static SSLCapabilities exploreHandshake(
+            ByteBuffer input, byte recordMajorVersion,
+            byte recordMinorVersion, int recordLength) throws IOException {
+
+        // What is the handshake type?
+        byte handshakeType = input.get();
+        if (handshakeType != 0x01) {   // 0x01: client_hello message
+            throw new IllegalStateException("Not initial handshaking");
+        }
+
+        // What is the handshake body length?
+        int handshakeLength = getInt24(input);
+
+        // Theoretically, a single handshake message might span multiple
+        // records, but in practice this does not occur.
+        if (handshakeLength > (recordLength - 4)) { // 4: handshake header size
+            throw new SSLException("Handshake message spans multiple records");
+        }
+
+        input = input.duplicate();
+        input.limit(handshakeLength + input.position());
+        return exploreClientHello(input,
+                recordMajorVersion, recordMinorVersion);
+    }
+
+    /*
+     * struct {
+     *     uint32 gmt_unix_time;
+     *     opaque random_bytes[28];
+     * } Random;
+     *
+     * opaque SessionID<0..32>;
+     *
+     * uint8 CipherSuite[2];
+     *
+     * enum { null(0), (255) } CompressionMethod;
+     *
+     * struct {
+     *     ProtocolVersion client_version;
+     *     Random random;
+     *     SessionID session_id;
+     *     CipherSuite cipher_suites<2..2^16-2>;
+     *     CompressionMethod compression_methods<1..2^8-1>;
+     *     select (extensions_present) {
+     *         case false:
+     *             struct {};
+     *         case true:
+     *             Extension extensions<0..2^16-1>;
+     *     };
+     * } ClientHello;
+     */
+    private static SSLCapabilities exploreClientHello(
+            ByteBuffer input,
+            byte recordMajorVersion,
+            byte recordMinorVersion) throws IOException {
+
+        List<SNIServerName> snList = Collections.<SNIServerName>emptyList();
+
+        // client version
+        byte helloMajorVersion = input.get();
+        byte helloMinorVersion = input.get();
+
+        // ignore random
+        int position = input.position();
+        input.position(position + 32);  // 32: the length of Random
+
+        // ignore session id
+        ignoreByteVector8(input);
+
+        // ignore cipher_suites
+        ignoreByteVector16(input);
+
+        // ignore compression methods
+        ignoreByteVector8(input);
+
+        if (input.remaining() > 0) {
+            snList = exploreExtensions(input);
+        }
+
+        return new SSLCapabilitiesImpl(
+                recordMajorVersion, recordMinorVersion,
+                helloMajorVersion, helloMinorVersion, snList);
+    }
+
+    /*
+     * struct {
+     *     ExtensionType extension_type;
+     *     opaque extension_data<0..2^16-1>;
+     * } Extension;
+     *
+     * enum {
+     *     server_name(0), max_fragment_length(1),
+     *     client_certificate_url(2), trusted_ca_keys(3),
+     *     truncated_hmac(4), status_request(5), (65535)
+     * } ExtensionType;
+     */
+    private static List<SNIServerName> exploreExtensions(ByteBuffer input)
+            throws IOException {
+
+        int length = getInt16(input);           // length of extensions
+        while (length > 0) {
+            int extType = getInt16(input);      // extenson type
+            int extLen = getInt16(input);       // length of extension data
+
+            if (extType == 0x00) {      // 0x00: type of server name indication
+                return exploreSNIExt(input, extLen);
+            } else {                    // ignore other extensions
+                ignoreByteVector(input, extLen);
+            }
+
+            length -= extLen + 4;
+        }
+
+        return Collections.<SNIServerName>emptyList();
+    }
+
+    /*
+     * struct {
+     *     NameType name_type;
+     *     select (name_type) {
+     *         case host_name: HostName;
+     *     } name;
+     * } ServerName;
+     *
+     * enum {
+     *     host_name(0), (255)
+     * } NameType;
+     *
+     * opaque HostName<1..2^16-1>;
+     *
+     * struct {
+     *     ServerName server_name_list<1..2^16-1>
+     * } ServerNameList;
+     */
+    private static List<SNIServerName> exploreSNIExt(ByteBuffer input,
+                                                     int extLen) throws IOException {
+
+        Map<Integer, SNIServerName> sniMap = new LinkedHashMap<>();
+
+        int remains = extLen;
+        if (extLen >= 2) {     // "server_name" extension in ClientHello
+            int listLen = getInt16(input);     // length of server_name_list
+            if (listLen == 0 || listLen + 2 != extLen) {
+                throw new SSLProtocolException(
+                        "Invalid server name indication extension");
+            }
+
+            remains -= 2;     // 0x02: the length field of server_name_list
+            while (remains > 0) {
+                int code = getInt8(input);      // name_type
+                int snLen = getInt16(input);    // length field of server name
+                if (snLen > remains) {
+                    throw new SSLProtocolException(
+                            "Not enough data to fill declared vector size");
+                }
+                byte[] encoded = new byte[snLen];
+                input.get(encoded);
+
+                SNIServerName serverName;
+                switch (code) {
+                    case StandardConstants.SNI_HOST_NAME:
+                        if (encoded.length == 0) {
+                            throw new SSLProtocolException(
+                                    "Empty HostName in server name indication");
+                        }
+                        serverName = new SNIHostName(encoded);
+                        break;
+                    default:
+                        serverName = new UnknownServerName(code, encoded);
+                }
+                // check for duplicated server name type
+                if (sniMap.put(serverName.getType(), serverName) != null) {
+                    throw new SSLProtocolException("Duplicated server name of type " + serverName.getType());
+                }
+
+                remains -= encoded.length + 3;  // NameType: 1 byte
+                // HostName length: 2 bytes
+            }
+        } else if (extLen == 0) {     // "server_name" extension in ServerHello
+            throw new SSLProtocolException(
+                    "Not server name indication extension in client");
+        }
+
+        if (remains != 0) {
+            throw new SSLProtocolException(
+                    "Invalid server name indication extension");
+        }
+
+        return Collections.<SNIServerName>unmodifiableList(
+                new ArrayList<>(sniMap.values()));
+    }
+
+    private static int getInt8(ByteBuffer input) {
+        return input.get();
+    }
+
+    private static int getInt16(ByteBuffer input) {
+        return ((input.get() & 0xFF) << 8) | (input.get() & 0xFF);
+    }
+
+    private static int getInt24(ByteBuffer input) {
+        return ((input.get() & 0xFF) << 16) | ((input.get() & 0xFF) << 8) | (input.get() & 0xFF);
+    }
+
+    private static void ignoreByteVector8(ByteBuffer input) {
+        ignoreByteVector(input, getInt8(input));
+    }
+
+    private static void ignoreByteVector16(ByteBuffer input) {
+        ignoreByteVector(input, getInt16(input));
+    }
+
+    private static void ignoreByteVector24(ByteBuffer input) {
+        ignoreByteVector(input, getInt24(input));
+    }
+
+    private static void ignoreByteVector(ByteBuffer input, int length) {
+        if (length != 0) {
+            int position = input.position();
+            input.position(position + length);
+        }
+    }
+
+    private static class UnknownServerName extends SNIServerName {
+        UnknownServerName(int code, byte[] encoded) {
+            super(code, encoded);
+        }
+    }
+
+    private static final class SSLCapabilitiesImpl extends SSLCapabilities {
+        private static final Map<Integer, String> versionMap = new HashMap<>(5);
+
+        private final String recordVersion;
+        private final String helloVersion;
+        List<SNIServerName> sniNames;
+
+        static {
+            versionMap.put(0x0002, "SSLv2Hello");
+            versionMap.put(0x0300, "SSLv3");
+            versionMap.put(0x0301, "TLSv1");
+            versionMap.put(0x0302, "TLSv1.1");
+            versionMap.put(0x0303, "TLSv1.2");
+        }
+
+        SSLCapabilitiesImpl(byte recordMajorVersion, byte recordMinorVersion,
+                            byte helloMajorVersion, byte helloMinorVersion,
+                            List<SNIServerName> sniNames) {
+
+            int version = (recordMajorVersion << 8) | recordMinorVersion;
+            this.recordVersion = versionMap.get(version) != null
+                    ? versionMap.get(version)
+                    : unknownVersion(recordMajorVersion, recordMinorVersion);
+
+            version = (helloMajorVersion << 8) | helloMinorVersion;
+            this.helloVersion = versionMap.get(version) != null
+                    ? versionMap.get(version)
+                    : unknownVersion(helloMajorVersion, helloMinorVersion);
+
+            this.sniNames = sniNames;
+        }
+
+        @Override
+        public String getRecordVersion() {
+            return recordVersion;
+        }
+
+        @Override
+        public String getHelloVersion() {
+            return helloVersion;
+        }
+
+        @Override
+        public List<SNIServerName> getServerNames() {
+            if (!sniNames.isEmpty()) {
+                return Collections.<SNIServerName>unmodifiableList(sniNames);
+            }
+
+            return sniNames;
+        }
+
+        private static String unknownVersion(byte major, byte minor) {
+            return "Unknown-" + ((int) major) + "." + ((int) minor);
+        }
+    }
+}
+
diff --git a/tests/e2e-tls/src/test/resources/hosts b/tests/e2e-tls/src/test/resources/hosts
new file mode 100644
index 0000000..438ebb6
--- /dev/null
+++ b/tests/e2e-tls/src/test/resources/hosts
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2023 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
+
+127.0.0.1   www.host0.com
+127.0.0.1	www.host1.com
+127.0.0.1	www.host2.com
+127.0.0.1   www.host3.com
\ No newline at end of file
diff --git a/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/MessageBodyWriterTest.java b/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/MessageBodyWriterTest.java
index 661cb46..d3d7fa9 100644
--- a/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/MessageBodyWriterTest.java
+++ b/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/MessageBodyWriterTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 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
@@ -21,6 +21,7 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
 
+import jakarta.inject.Inject;
 import jakarta.ws.rs.GET;
 import jakarta.ws.rs.HeaderParam;
 import jakarta.ws.rs.POST;
@@ -32,7 +33,6 @@
 import jakarta.ws.rs.client.Entity;
 import jakarta.ws.rs.core.Application;
 import jakarta.ws.rs.core.Configuration;
-import jakarta.ws.rs.core.Context;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.MultivaluedMap;
 import jakarta.ws.rs.core.Response;
@@ -75,9 +75,13 @@
     @Provider
     @Produces("text/plain")
     public static class OverridingStringProvider implements MessageBodyWriter<String> {
+        private final Configuration config;
 
-        @Context
-        private Configuration config;
+        @Inject
+        public OverridingStringProvider(Configuration config) {
+            this.config = config;
+        }
+
 
         @Override
         public boolean isWriteable(
@@ -120,10 +124,13 @@
     @Provider
     @Produces("text/html")
     public static class HtmlStringProvider implements MessageBodyWriter<String> {
-
-        @Context
         private Configuration config;
 
+        @Inject
+        public HtmlStringProvider(Configuration config) {
+            this.config = config;
+        }
+
         @Override
         public boolean isWriteable(
                 final Class<?> type,
diff --git a/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/common/LoggingFeatureTest.java b/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/common/LoggingFeatureTest.java
index 9958cd9..cd54930 100644
--- a/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/common/LoggingFeatureTest.java
+++ b/tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/common/LoggingFeatureTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2023 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,6 +19,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.logging.Level;
@@ -707,29 +708,36 @@
 
             // --- client request log entry
             // client added header before request has sent (and logged)
-            assertThat(getLoggedRecords().get(0).getMessage(),
+            Iterator<LogRecord> it = getLoggedRecords().iterator();
+            LogRecord logRecord = it.next();
+            while (logRecord.getLevel() == Level.WARNING) { // Skip any warning at the beginning
+                logRecord = it.next();
+            }
+            assertThat(logRecord.getMessage(),
                     containsString("1 > custom_header: client/request\n"));
 
 
             // --- container request log entry
             // container receives header from client request
-            assertThat(getLoggedRecords().get(1).getMessage(),
+            logRecord = it.next();
+            assertThat(logRecord.getMessage(),
                     containsString("1 > custom_header: client/request\n"));
             // container has added its own header after logging filter logged message
-            assertThat(getLoggedRecords().get(1).getMessage(),
+            assertThat(logRecord.getMessage(),
                     not(containsString("1 > custom_header: container/request\n")));
 
 
             // --- container response log entry
             // container added header to the response and it was logged
-            assertThat(getLoggedRecords().get(2).getMessage(),
+            assertThat(it.next().getMessage(),
                     containsString("1 < custom_header: container/response\n"));
 
             // --- client response log entry
             // client received header
-            assertThat(getLoggedRecords().get(3).getMessage(),
+            logRecord = it.next();
+            assertThat(logRecord.getMessage(),
                     containsString("1 < custom_header: container/response\n"));
-            assertThat(getLoggedRecords().get(3).getMessage(),
+            assertThat(logRecord.getMessage(),
                     not(containsString("1 < custom_header: client/response\n")));
 
         }
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 cdca445..c6ecc29 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, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2023 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 org.glassfish.jersey.ExternalProperties;
 import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.TestProperties;
 import org.glassfish.jersey.test.jetty.JettyTestContainerFactory;
 import org.glassfish.jersey.test.spi.TestContainerException;
 import org.glassfish.jersey.test.spi.TestContainerFactory;
@@ -37,9 +38,12 @@
 import jakarta.ws.rs.core.Response;
 
 public class HttpProxyTest extends JerseyTest {
+    public HttpProxyTest() {
+        set(TestProperties.CONTAINER_PORT, 0);
+    }
 
     private static final String PROXY_HOST = "localhost";
-    private static final String PROXY_PORT = "9997";
+    private static final String PROXY_PORT = "0";
     private static boolean proxyHit = false;
 
     @Path("resource")
@@ -60,7 +64,6 @@
     @BeforeEach
     public void startFakeProxy() {
         System.setProperty(ExternalProperties.HTTP_PROXY_HOST, PROXY_HOST);
-        System.setProperty(ExternalProperties.HTTP_PROXY_PORT, PROXY_PORT);
         Server server = new Server(Integer.parseInt(PROXY_PORT));
         server.setHandler(new ProxyHandler(false));
         try {
@@ -68,6 +71,7 @@
         } catch (Exception e) {
 
         }
+        System.setProperty(ExternalProperties.HTTP_PROXY_PORT, String.valueOf(server.getURI().getPort()));
     }
 
     @Override
diff --git a/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/ApplicationResource.java b/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/ApplicationResource.java
index 7c927f2..1c7d2c0 100644
--- a/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/ApplicationResource.java
+++ b/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/ApplicationResource.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2023 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
@@ -21,6 +21,7 @@
 
 import jakarta.json.JsonValue;
 import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.FormParam;
 import jakarta.ws.rs.GET;
 import jakarta.ws.rs.HeaderParam;
 import jakarta.ws.rs.POST;
@@ -76,4 +77,10 @@
     @Path("content1/{content1}/content0/{content0: [0-9]{4}}")
     @Produces(MediaType.TEXT_PLAIN)
     String regex0(@PathParam("content1") String context0, @PathParam("content0") String context1);
+
+    @POST
+    @Path("formParam")
+    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+    @Produces(MediaType.TEXT_PLAIN)
+    String formParam(@FormParam("param") String param);
 }
diff --git a/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/ApplicationResourceImpl.java b/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/ApplicationResourceImpl.java
index dd10f72..56dc5bd 100644
--- a/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/ApplicationResourceImpl.java
+++ b/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/ApplicationResourceImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2023 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
@@ -71,4 +71,9 @@
     public String regex0(String context0, String context1) {
         return context0 + "_" + context1;
     }
+
+    @Override
+    public String formParam(String param) {
+        return param;
+    }
 }
diff --git a/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/RestClientModelTest.java b/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/RestClientModelTest.java
index 24c0308..469b215 100644
--- a/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/RestClientModelTest.java
+++ b/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/RestClientModelTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2023 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
@@ -56,4 +56,12 @@
 
         assertEquals("Hi", app.sayHi());
     }
+
+    @Test
+    public void testFormParam() throws URISyntaxException {
+        String response = RestClientBuilder.newBuilder()
+                .baseUri(new URI("http://localhost:9998"))
+                .build(ApplicationResource.class).formParam(null);
+        assertEquals("", response);
+    }
 }
diff --git a/tests/pom.xml b/tests/pom.xml
index 946aa00..025ebb1 100644
--- a/tests/pom.xml
+++ b/tests/pom.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
 
-    Copyright (c) 2011, 2022 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2011, 2023 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
@@ -44,6 +44,7 @@
         <module>e2e-inject</module>
         <module>e2e-server</module>
         <module>e2e-testng</module>
+        <module>e2e-tls</module>
         <module>integration</module>
         <module>jmockit</module>
         <module>mem-leaks</module>
@@ -105,5 +106,14 @@
                 </plugins>
             </build>
         </profile>
+        <profile>
+            <id>JDK11+</id>
+            <activation>
+                <jdk>[11,)</jdk>
+            </activation>
+            <modules>
+                <module>release-test</module>
+            </modules>
+        </profile>
     </profiles>
 </project>
diff --git a/tests/release-test/pom.xml b/tests/release-test/pom.xml
index 3d58845..e5dc66c 100644
--- a/tests/release-test/pom.xml
+++ b/tests/release-test/pom.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
 
-    Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2022, 2023 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
@@ -21,22 +21,20 @@
     <modelVersion>4.0.0</modelVersion>
 
     <parent>
-        <groupId>org.eclipse.ee4j</groupId>
+        <groupId>org.glassfish.jersey</groupId>
         <artifactId>project</artifactId>
-        <version>1.0.8</version>
-        <relativePath>../../../pom.xml</relativePath>
+        <version>3.0.99-SNAPSHOT</version>
+        <relativePath>../../pom.xml</relativePath>
     </parent>
 
     <groupId>org.glassfish.jersey.tests</groupId>
     <artifactId>release-test</artifactId>
-    <version>3.0.99-SNAPSHOT</version>
     <packaging>jar</packaging>
     <name>jersey-release-test</name>
 
     <description>Jersey post-release validation tests</description>
 
     <properties>
-        <jersey.version>${jersey.version}</jersey.version> <!-- Must pass using -Djersey.version= -->
         <maven.compiler.source>11</maven.compiler.source>
         <maven.compiler.target>11</maven.compiler.target>
         <maven.version>3.8.6</maven.version>
@@ -54,8 +52,7 @@
                     <reuseForks>false</reuseForks>
                     <enableAssertions>false</enableAssertions>
                     <includes>
-                        <include>**/DownloadBomPomDependencies.java</include>
-                        <include>**/*Test.class</include>
+                        <include>**/NoticeFilesTest.class</include>
                     </includes>
                 </configuration>
             </plugin>
@@ -117,6 +114,60 @@
             <groupId>org.apache.maven.resolver</groupId>
             <artifactId>maven-resolver-transport-http</artifactId>
             <version>${maven.resolver.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.httpcomponents</groupId>
+                    <artifactId>httpcore</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-common</artifactId>
         </dependency>
     </dependencies>
+
+    <profiles>
+        <profile>
+            <id>ReleaseTests</id>
+            <activation>
+                <property>
+                    <name>jersey.version</name>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <version>3.0.0-M7</version>
+                        <configuration>
+                            <forkCount>1</forkCount>
+                            <reuseForks>false</reuseForks>
+                            <enableAssertions>false</enableAssertions>
+                            <includes>
+                                <include>**/DownloadBomPomDependencies.java</include>
+                                <include>**/*Test.class</include>
+                            </includes>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+            <dependencyManagement>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.glassfish.jersey</groupId>
+                        <artifactId>jersey-bom</artifactId>
+                        <version>${jersey.version}</version>
+                        <scope>import</scope>
+                        <type>pom</type>
+                    </dependency>
+                </dependencies>
+            </dependencyManagement>
+            <properties>
+                <jersey.version>${jersey.version}</jersey.version> <!-- Must pass using -Djersey.version= -->
+            </properties>
+        </profile>
+    </profiles>
 </project>
diff --git a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/ClassVersionChecker.java b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/ClassVersionChecker.java
index 43e5327..743d609 100644
--- a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/ClassVersionChecker.java
+++ b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/ClassVersionChecker.java
@@ -1,13 +1,17 @@
 /*
- * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2023 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,
- * or the Eclipse Distribution License v. 1.0 which is available at
- * http://www.eclipse.org/org/documents/edl-v10.php.
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
  *
- * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ * 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.test.artifacts;
diff --git a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/DependencyPair.java b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/DependencyPair.java
index dd31588..3256d48 100644
--- a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/DependencyPair.java
+++ b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/DependencyPair.java
@@ -1,13 +1,17 @@
 /*
- * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2023 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,
- * or the Eclipse Distribution License v. 1.0 which is available at
- * http://www.eclipse.org/org/documents/edl-v10.php.
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
  *
- * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ * 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.test.artifacts;
diff --git a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/DependencyResolver.java b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/DependencyResolver.java
index 5df3bc1..b1a7ee3 100644
--- a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/DependencyResolver.java
+++ b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/DependencyResolver.java
@@ -1,13 +1,17 @@
 /*
- * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2023 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,
- * or the Eclipse Distribution License v. 1.0 which is available at
- * http://www.eclipse.org/org/documents/edl-v10.php.
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
  *
- * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ * 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.test.artifacts;
diff --git a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/MavenUtil.java b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/MavenUtil.java
index 2c5b3a2..68d0a14 100644
--- a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/MavenUtil.java
+++ b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/MavenUtil.java
@@ -1,14 +1,19 @@
 /*
- * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2023 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,
- * or the Eclipse Distribution License v. 1.0 which is available at
- * http://www.eclipse.org/org/documents/edl-v10.php.
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
  *
- * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ * 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.test.artifacts;
 
 import org.apache.maven.model.Dependency;
@@ -103,7 +108,7 @@
                 .filter(dep -> dep.getType().equals("jar"));
     }
 
-    private static Model getModelFromFile(String fileName) throws IOException, XmlPullParserException {
+    static Model getModelFromFile(String fileName) throws IOException, XmlPullParserException {
         File pomFile = new File(fileName);
         return getModelFromFile(pomFile);
     }
diff --git a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/TestResult.java b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/TestResult.java
index 172c596..5c357fc 100644
--- a/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/TestResult.java
+++ b/tests/release-test/src/main/java/org/glassfish/jersey/test/artifacts/TestResult.java
@@ -1,14 +1,19 @@
 /*
- * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2023 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,
- * or the Eclipse Distribution License v. 1.0 which is available at
- * http://www.eclipse.org/org/documents/edl-v10.php.
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
  *
- * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ * 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.test.artifacts;
 
 import java.io.IOException;
@@ -53,24 +58,24 @@
         }
 
         @Override
-        public MessageBuilder append(CharSequence csq) throws IOException {
+        public MessageBuilder append(CharSequence csq) {
             builder.append(csq);
             return this;
         }
 
-        public MessageBuilder append(int i) throws IOException {
+        public MessageBuilder append(int i) {
             builder.append(i);
             return this;
         }
 
         @Override
-        public MessageBuilder append(CharSequence csq, int start, int end) throws IOException {
+        public MessageBuilder append(CharSequence csq, int start, int end) {
             builder.append(csq, start, end);
             return this;
         }
 
         @Override
-        public MessageBuilder append(char c) throws IOException {
+        public MessageBuilder append(char c) {
             builder.append(c);
             return this;
         }
diff --git a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/DownloadBomPomDependencies.java b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/DownloadBomPomDependencies.java
index ef31d4e..01ba01e 100644
--- a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/DownloadBomPomDependencies.java
+++ b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/DownloadBomPomDependencies.java
@@ -1,14 +1,19 @@
 /*
- * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2023 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,
- * or the Eclipse Distribution License v. 1.0 which is available at
- * http://www.eclipse.org/org/documents/edl-v10.php.
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
  *
- * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ * 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.test.artifacts;
 
 import org.eclipse.aether.DefaultRepositorySystemSession;
diff --git a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/ManifestTest.java b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/ManifestTest.java
index 8da0835..0c77d69 100644
--- a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/ManifestTest.java
+++ b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/ManifestTest.java
@@ -1,13 +1,17 @@
 /*
- * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2023 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,
- * or the Eclipse Distribution License v. 1.0 which is available at
- * http://www.eclipse.org/org/documents/edl-v10.php.
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
  *
- * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ * 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.test.artifacts;
 
@@ -28,7 +32,7 @@
 
     private static final String BUNDLE_NAME_ATTRIBUTE = "Bundle-Name";
     private static final String BUNDLE_VERSION_ATTRIBUTE = "Bundle-Version";
-    private static final String [] EXCLUDED_JARS = {"test", "rx-client", "oauth", "weld2-se", "spring",
+    private static final String[] EXCLUDED_JARS = {"test", "rx-client", "oauth", "weld2-se", "spring",
             "servlet-portability", /* obsolete */
             "helidon-connector", /* Helidon does not contain OSGi headers */
             "grizzly-connector", /* Limited maintenance */
diff --git a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/MultiReleaseTest.java b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/MultiReleaseTest.java
index deef29a..288932a 100644
--- a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/MultiReleaseTest.java
+++ b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/MultiReleaseTest.java
@@ -1,13 +1,17 @@
 /*
- * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2023 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,
- * or the Eclipse Distribution License v. 1.0 which is available at
- * http://www.eclipse.org/org/documents/edl-v10.php.
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
  *
- * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ * 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.test.artifacts;
diff --git a/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/NoticeFilesTest.java b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/NoticeFilesTest.java
new file mode 100644
index 0000000..6cda528
--- /dev/null
+++ b/tests/release-test/src/test/java/org/glassfish/jersey/test/artifacts/NoticeFilesTest.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2023 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.test.artifacts;
+
+import org.apache.maven.model.Model;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.glassfish.jersey.message.internal.ReaderWriter;
+import org.junit.Assert;
+import org.junit.Test;
+
+import jakarta.ws.rs.core.MediaType;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.regex.Pattern;
+
+public class NoticeFilesTest {
+
+    @Test
+    public void test() throws IOException, XmlPullParserException {
+        Model model = MavenUtil.getModelFromFile("../../pom.xml");
+        List<NoticeDependencyVersionPair> mainExpectedNoticeDeps = mainExpectedDependencies();
+
+        File mainNotice = new File("../../NOTICE.md");
+        List<NoticeDependencyVersionPair> mainNoticeDeps = parseNoticeFileVersions(mainNotice);
+        TestResult testResult = compareDependencies(mainExpectedNoticeDeps, mainNoticeDeps, model, mainNotice.getCanonicalPath());
+
+        // Nothing to check here, yet
+//        File commonNotice = new File("../../core-common/src/main/resources/META-INF/NOTICE.markdown");
+//        List<NoticeDependencyVersionPair> commonNoticeDeps = parseNoticeFileVersions(mainNotice);
+//        testResult.append(compareDependencies(expectedNoticeDeps, commonNoticeDeps, model, commonNotice.getCanonicalPath()));
+
+        File serverNotice = new File("../../core-server/src/main/resources/META-INF/NOTICE.markdown");
+        List<NoticeDependencyVersionPair> serverNoticeDeps = parseNoticeFileVersions(serverNotice);
+        List<NoticeDependencyVersionPair> serverExpectedNoticeDeps = serverExpectedDependencies();
+        testResult.append(
+                compareDependencies(serverExpectedNoticeDeps, serverNoticeDeps, model, serverNotice.getCanonicalPath()));
+
+        File jacksonNotice = new File("../../media/json-jackson/src/main/resources/META-INF/NOTICE.markdown");
+        List<NoticeDependencyVersionPair> jacksonNoticeDeps = parseNoticeFileVersions(jacksonNotice);
+        List<NoticeDependencyVersionPair> jacksonExpectedNoticeDeps = jacksonExpectedDependencies();
+        testResult.append(
+                compareDependencies(jacksonExpectedNoticeDeps, jacksonNoticeDeps, model, jacksonNotice.getCanonicalPath()));
+
+        File bvNotice = new File("../../ext/bean-validation/src/main/resources/META-INF/NOTICE.markdown");
+        List<NoticeDependencyVersionPair> bvNoticeDeps = parseNoticeFileVersions(bvNotice);
+        List<NoticeDependencyVersionPair> bvExpectedNoticeDeps = bvExpectedDependencies();
+        testResult.append(
+                compareDependencies(bvExpectedNoticeDeps, bvNoticeDeps, model, bvNotice.getCanonicalPath()));
+
+        File examplesNotice = new File("../../examples/NOTICE.md");
+        List<NoticeDependencyVersionPair> examplesNoticeDeps = parseNoticeFileVersions(examplesNotice);
+        testResult.append(
+                compareDependencies(mainExpectedNoticeDeps, examplesNoticeDeps, model, examplesNotice.getCanonicalPath()));
+
+        Assert.assertTrue("Some error occurred, see previous messages", testResult.result());
+    }
+
+    private TestResult compareDependencies(List<NoticeDependencyVersionPair> expectedDeps,
+                                     List<NoticeDependencyVersionPair> actualDeps,
+                                     Model model, String noticeName) {
+        TestResult testResult = new TestResult();
+        NextExpected:
+        for (NoticeDependencyVersionPair expectedDep : expectedDeps) {
+            for (NoticeDependencyVersionPair actualDep : actualDeps) {
+                if (expectedDep.dependency.equals(actualDep.dependency)) {
+                    String expectedVersion = findVersionInModel(expectedDep, model);
+                    testResult.ok().append("Expected dependency ").append(expectedDep.dependency).println(" found");
+                    if (expectedVersion.equals(actualDep.version)) {
+                        testResult.ok().append("Dependency ").append(actualDep.dependency).append(" contains expected version ")
+                                .append(expectedVersion).append(" in ").println(noticeName);
+                    } else {
+                        testResult.exception().append("Dependency ").append(actualDep.dependency).append(" differs version ")
+                                .append(expectedVersion).append(" from ").append(noticeName).append(" version ")
+                                .println(actualDep.version);
+                    }
+                    continue NextExpected;
+                }
+            }
+            testResult.exception().append("Expected dependency ").append(expectedDep.dependency).append(" not found in ")
+                    .println(noticeName);
+        }
+        return testResult;
+    }
+
+    private static String findVersionInModel(NoticeDependencyVersionPair pair, Model model) {
+        if (pair.version.startsWith("${")) {
+            String version = pair.version.substring(2, pair.version.length() - 1);
+            return model.getProperties().getProperty(version);
+        } else {
+            return pair.version;
+        }
+    }
+
+    private void cat(File path) throws IOException {
+        StringTokenizer tokenizer = tokenizerFromNoticeFile(path);
+        while (tokenizer.hasMoreTokens()) {
+            String token = tokenizer.nextToken();
+            if (token.trim().length() > 1 && !token.trim().startsWith("*")) {
+                System.out.println(token);
+//                String filteredToken = removeUnnecessary(token);
+//                System.out.println(filteredToken);
+//                Pattern versionizer = Pattern.compile("([.*])?([\\d])");
+//                System.out.println(versionizer.matcher(filteredToken).replaceFirst("$1:$2"));
+            }
+        }
+    }
+
+    private List<NoticeDependencyVersionPair> parseNoticeFileVersions(File path) throws IOException {
+        List<NoticeDependencyVersionPair> list = new LinkedList<>();
+        StringTokenizer tokenizer = tokenizerFromNoticeFile(path);
+        while (tokenizer.hasMoreTokens()) {
+            String token = tokenizer.nextToken();
+            if (token.trim().length() > 1 && !token.trim().startsWith("*")) {
+                String filteredToken = removeUnnecessary(token);
+                Pattern versionizer = Pattern.compile("([.*])?([\\d])");
+                String[] args = versionizer.matcher(filteredToken).replaceFirst("$1:$2").split(":", 2);
+                NoticeDependencyVersionPair pair = args.length == 2
+                        ? new NoticeDependencyVersionPair(args[0], args[1])
+                        : new NoticeDependencyVersionPair(args[0], "");
+                list.add(pair);
+            }
+        }
+
+        return list;
+    }
+
+    private StringTokenizer tokenizerFromNoticeFile(File path) throws IOException {
+        StringTokenizer tokenizer = new StringTokenizer(getFile(path), "\n");
+        while (tokenizer.hasMoreTokens()) {
+            String token = tokenizer.nextToken();
+            if (token.trim().startsWith("## Third-party Content")) {
+                break;
+            }
+        }
+        return tokenizer;
+    }
+
+    private String getFile(File path) throws IOException {
+        return ReaderWriter.readFromAsString(new FileInputStream(path), MediaType.TEXT_PLAIN_TYPE);
+    }
+
+    private String removeUnnecessary(String dependency) {
+        String filtered = dependency
+                .replace(" Version ", "").replace(" version ", "")
+                .replace(" API ", "")
+                .replace(" v", "")
+                .replace(", ", "").replace(",", "")
+                .replace(": ", "").replace(": ", "");
+        return filtered;
+    }
+
+    /**
+     * Return pair of Notice file dependency name & pom.xml version property name
+     */
+    private List<NoticeDependencyVersionPair> mainExpectedDependencies() {
+        final List<NoticeDependencyVersionPair> dependencyPairs = new LinkedList<>();
+        dependencyPairs.add(new NoticeDependencyVersionPair("org.objectweb.asm", "${asm.version}"));
+        dependencyPairs.add(new NoticeDependencyVersionPair("org.osgi.core", "${osgi.version}"));
+        dependencyPairs.add(new NoticeDependencyVersionPair("Jackson JAX-RS Providers", "${jackson.version}"));
+        dependencyPairs.add(new NoticeDependencyVersionPair("Javassist", "${javassist.version}"));
+        dependencyPairs.add(new NoticeDependencyVersionPair("Hibernate Validator CDI", "${validation.impl.version}"));
+        dependencyPairs.add(new NoticeDependencyVersionPair("Bean Validation", "${jakarta.validation.api.version}"));
+        return dependencyPairs;
+    }
+
+    private List<NoticeDependencyVersionPair> serverExpectedDependencies() {
+        final List<NoticeDependencyVersionPair> dependencyPairs = new LinkedList<>();
+        dependencyPairs.add(new NoticeDependencyVersionPair("org.objectweb.asm", "${asm.version}"));
+        return dependencyPairs;
+    }
+
+    private List<NoticeDependencyVersionPair> bvExpectedDependencies() {
+        final List<NoticeDependencyVersionPair> dependencyPairs = new LinkedList<>();
+        dependencyPairs.add(new NoticeDependencyVersionPair("Hibernate Validator CDI", "${validation.impl.version}"));
+        return dependencyPairs;
+    }
+
+    private List<NoticeDependencyVersionPair> jacksonExpectedDependencies() {
+        final List<NoticeDependencyVersionPair> dependencyPairs = new LinkedList<>();
+        dependencyPairs.add(new NoticeDependencyVersionPair("Jackson JAX-RS Providers", "${jackson.version}"));
+        return dependencyPairs;
+    }
+
+    private static class NoticeDependencyVersionPair {
+        private final String dependency;
+        private final String version;
+
+        private NoticeDependencyVersionPair(String dependency, String version) {
+            this.dependency = dependency.trim();
+            this.version = version.trim();
+        }
+    }
+}