Allow for using HeaderDelegateProvider service  (#4276)

* Allow for using HeaderDelegateProvider service if CommonProperties#METAINF_SERVICES_LOOKUP_DISABLE is not true

Signed-off-by: Jan Supol <jan.supol@oracle.com>
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 16a1131..784f69c 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
@@ -456,7 +456,7 @@
     @Override
     public ClientResponse apply(final ClientRequest clientRequest) throws ProcessingException {
         final HttpUriRequest request = getUriHttpRequest(clientRequest);
-        final Map<String, String> clientHeadersSnapshot = writeOutBoundHeaders(clientRequest.getHeaders(), request);
+        final Map<String, String> clientHeadersSnapshot = writeOutBoundHeaders(clientRequest, request);
 
         try {
             final CloseableHttpResponse response;
@@ -476,7 +476,8 @@
             }
 
             response = client.execute(getHost(request), request, context);
-            HeaderUtils.checkHeaderChanges(clientHeadersSnapshot, clientRequest.getHeaders(), this.getClass().getName());
+            HeaderUtils.checkHeaderChanges(clientHeadersSnapshot, clientRequest.getHeaders(),
+                    this.getClass().getName(), clientRequest.getConfiguration());
 
             final Response.StatusType status = response.getStatusLine().getReasonPhrase() == null
                     ? Statuses.from(response.getStatusLine().getStatusCode())
@@ -643,9 +644,10 @@
         }
     }
 
-    private static Map<String, String> writeOutBoundHeaders(final MultivaluedMap<String, Object> headers,
+    private static Map<String, String> writeOutBoundHeaders(final ClientRequest clientRequest,
                                                             final HttpUriRequest request) {
-        final Map<String, String> stringHeaders = HeaderUtils.asStringHeadersSingleValue(headers);
+        final Map<String, String> stringHeaders =
+                HeaderUtils.asStringHeadersSingleValue(clientRequest.getHeaders(), clientRequest.getConfiguration());
 
         for (final Map.Entry<String, String> e : stringHeaders.entrySet()) {
             request.addHeader(e.getKey(), e.getValue());
diff --git a/connectors/grizzly-connector/src/main/java/org/glassfish/jersey/grizzly/connector/GrizzlyConnector.java b/connectors/grizzly-connector/src/main/java/org/glassfish/jersey/grizzly/connector/GrizzlyConnector.java
index e4428d5..ced8f43 100644
--- a/connectors/grizzly-connector/src/main/java/org/glassfish/jersey/grizzly/connector/GrizzlyConnector.java
+++ b/connectors/grizzly-connector/src/main/java/org/glassfish/jersey/grizzly/connector/GrizzlyConnector.java
@@ -33,7 +33,6 @@
 import javax.ws.rs.ProcessingException;
 import javax.ws.rs.client.Client;
 import javax.ws.rs.core.Configuration;
-import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 
 import org.glassfish.jersey.client.ClientProperties;
@@ -178,7 +177,7 @@
     @Override
     public ClientResponse apply(final ClientRequest request) {
         final Request connectorRequest = translate(request);
-        final Map<String, String> clientHeadersSnapshot = writeOutBoundHeaders(request.getHeaders(), connectorRequest);
+        final Map<String, String> clientHeadersSnapshot = writeOutBoundHeaders(request, connectorRequest);
 
         final CompletableFuture<ClientResponse> responseFuture = new CompletableFuture<>();
         final ByteBufferInputStream entityStream = new ByteBufferInputStream();
@@ -201,7 +200,8 @@
                     }
 
                     HeaderUtils.checkHeaderChanges(clientHeadersSnapshot, request.getHeaders(),
-                                                   GrizzlyConnector.this.getClass().getName());
+                                                   GrizzlyConnector.this.getClass().getName(),
+                                                   request.getConfiguration());
 
                     responseFuture.complete(translate(request, this.status, headers, entityStream));
                     return STATE.CONTINUE;
@@ -242,7 +242,7 @@
     @Override
     public Future<?> apply(final ClientRequest request, final AsyncConnectorCallback callback) {
         final Request connectorRequest = translate(request);
-        final Map<String, String> clientHeadersSnapshot = writeOutBoundHeaders(request.getHeaders(), connectorRequest);
+        final Map<String, String> clientHeadersSnapshot = writeOutBoundHeaders(request, connectorRequest);
         final ByteBufferInputStream entityStream = new ByteBufferInputStream();
         final AtomicBoolean callbackInvoked = new AtomicBoolean(false);
 
@@ -264,7 +264,7 @@
                     }
 
                     HeaderUtils.checkHeaderChanges(clientHeadersSnapshot, request.getHeaders(),
-                            GrizzlyConnector.this.getClass().getName());
+                            GrizzlyConnector.this.getClass().getName(), request.getConfiguration());
                     // hand-off to grizzly's application thread pool for response processing
                     processResponse(new Runnable() {
                         @Override
@@ -462,9 +462,10 @@
         return baos.toByteArray();
     }
 
-    private static Map<String, String> writeOutBoundHeaders(final MultivaluedMap<String, Object> headers,
+    private static Map<String, String> writeOutBoundHeaders(final ClientRequest clientRequest,
                                                             final com.ning.http.client.Request request) {
-        Map<String, String> stringHeaders = HeaderUtils.asStringHeadersSingleValue(headers);
+        Map<String, String> stringHeaders =
+                HeaderUtils.asStringHeadersSingleValue(clientRequest.getHeaders(), clientRequest.getConfiguration());
 
         for (Map.Entry<String, String> e : stringHeaders.entrySet()) {
             request.getHeaders().add(e.getKey(), e.getValue());
diff --git a/connectors/jetty-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnector.java b/connectors/jetty-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnector.java
index fc87414..d9b42fa 100644
--- a/connectors/jetty-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnector.java
+++ b/connectors/jetty-connector/src/main/java/org/glassfish/jersey/jetty/connector/JettyConnector.java
@@ -129,6 +129,7 @@
 
     private final HttpClient client;
     private final CookieStore cookieStore;
+    private final Configuration configuration;
 
     /**
      * Create the new Jetty client connector.
@@ -137,6 +138,7 @@
      * @param config client configuration.
      */
     JettyConnector(final Client jaxrsClient, final Configuration config) {
+        this.configuration = config;
         HttpClient httpClient = null;
         if (config.isRegistered(JettyHttpClientSupplier.class)) {
             Optional<Object> contract = config.getInstances().stream()
@@ -248,7 +250,7 @@
         try {
             final ContentResponse jettyResponse = jettyRequest.send();
             HeaderUtils.checkHeaderChanges(clientHeadersSnapshot, jerseyRequest.getHeaders(),
-                                           JettyConnector.this.getClass().getName());
+                                           JettyConnector.this.getClass().getName(), jerseyRequest.getConfiguration());
 
             final javax.ws.rs.core.Response.StatusType status = jettyResponse.getReason() == null
                     ? Statuses.from(jettyResponse.getStatus())
@@ -306,8 +308,8 @@
         return request;
     }
 
-    private static Map<String, String> writeOutBoundHeaders(final MultivaluedMap<String, Object> headers, final Request request) {
-        final Map<String, String> stringHeaders = HeaderUtils.asStringHeadersSingleValue(headers);
+    private Map<String, String> writeOutBoundHeaders(final MultivaluedMap<String, Object> headers, final Request request) {
+        final Map<String, String> stringHeaders = HeaderUtils.asStringHeadersSingleValue(headers, configuration);
 
         // remove User-agent header set by Jetty; Jersey already sets this in its request (incl. Jetty version)
         request.getHeaders().remove(HttpHeader.USER_AGENT);
@@ -396,7 +398,7 @@
                 @Override
                 public void onHeaders(final Response jettyResponse) {
                     HeaderUtils.checkHeaderChanges(clientHeadersSnapshot, jerseyRequest.getHeaders(),
-                                                   JettyConnector.this.getClass().getName());
+                                                   JettyConnector.this.getClass().getName(), jerseyRequest.getConfiguration());
 
                     if (responseFuture.isDone()) {
                         if (!callbackInvoked.compareAndSet(false, true)) {
diff --git a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpContainer.java b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpContainer.java
index f906ca1..3519624 100644
--- a/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpContainer.java
+++ b/containers/grizzly2-http/src/main/java/org/glassfish/jersey/grizzly2/httpserver/GrizzlyHttpContainer.java
@@ -338,8 +338,11 @@
             URI baseUri = getBaseUri(request);
             URI requestUri = getRequestUri(request);
             final ContainerRequest requestContext = new ContainerRequest(baseUri,
-                    requestUri, request.getMethod().getMethodString(),
-                    getSecurityContext(request), new GrizzlyRequestPropertiesDelegate(request));
+                    requestUri,
+                    request.getMethod().getMethodString(),
+                    getSecurityContext(request),
+                    new GrizzlyRequestPropertiesDelegate(request),
+                    appHandler.getConfiguration());
             requestContext.setEntityStream(request.getInputStream());
             for (final String headerName : request.getHeaderNames()) {
                 requestContext.headers(headerName, request.getHeaders(headerName));
diff --git a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpHandlerContainer.java b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpHandlerContainer.java
index 265e9e3..4f6cb30 100644
--- a/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpHandlerContainer.java
+++ b/containers/jdk-http/src/main/java/org/glassfish/jersey/jdkhttp/JdkHttpHandlerContainer.java
@@ -127,7 +127,7 @@
         final ResponseWriter responseWriter = new ResponseWriter(exchange);
         final ContainerRequest requestContext = new ContainerRequest(baseUri, requestUri,
                 exchange.getRequestMethod(), getSecurityContext(exchange.getPrincipal(), isSecure),
-                new MapPropertiesDelegate());
+                new MapPropertiesDelegate(), appHandler.getConfiguration());
         requestContext.setEntityStream(exchange.getRequestBody());
         requestContext.getHeaders().putAll(exchange.getRequestHeaders());
         requestContext.setWriter(responseWriter);
diff --git a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/WebComponent.java b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/WebComponent.java
index 35c1499..1938ed3 100644
--- a/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/WebComponent.java
+++ b/containers/jersey-servlet-core/src/main/java/org/glassfish/jersey/servlet/WebComponent.java
@@ -385,7 +385,9 @@
 
         try {
             final ContainerRequest requestContext = new ContainerRequest(baseUri, requestUri, servletRequest.getMethod(),
-                    getSecurityContext(servletRequest), new ServletPropertiesDelegate(servletRequest));
+                    getSecurityContext(servletRequest), new ServletPropertiesDelegate(servletRequest),
+                    appHandler.getConfiguration()
+            );
 
             initContainerRequest(requestContext, servletRequest, servletResponse, responseWriter);
 
diff --git a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java
index 592c55c..5fa394d 100644
--- a/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java
+++ b/containers/jetty-http/src/main/java/org/glassfish/jersey/jetty/JettyHttpContainer.java
@@ -151,7 +151,8 @@
                     requestUri,
                     request.getMethod(),
                     getSecurityContext(request),
-                    new MapPropertiesDelegate());
+                    new MapPropertiesDelegate(),
+                    appHandler.getConfiguration());
             requestContext.setEntityStream(request.getInputStream());
             final Enumeration<String> headerNames = request.getHeaderNames();
             while (headerNames.hasMoreElements()) {
diff --git a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/HttpVersionChooser.java b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/HttpVersionChooser.java
index 20af41f..320d7ba 100644
--- a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/HttpVersionChooser.java
+++ b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/HttpVersionChooser.java
@@ -24,6 +24,7 @@
 import io.netty.handler.ssl.ApplicationProtocolNames;
 import io.netty.handler.ssl.ApplicationProtocolNegotiationHandler;
 import io.netty.handler.stream.ChunkedWriteHandler;
+import org.glassfish.jersey.server.ResourceConfig;
 
 /**
  * Choose the handler implementation based on Http protocol.
@@ -34,26 +35,28 @@
 
     private final URI baseUri;
     private final NettyHttpContainer container;
+    private final ResourceConfig resourceConfig;
 
-    HttpVersionChooser(URI baseUri, NettyHttpContainer container) {
+    HttpVersionChooser(URI baseUri, NettyHttpContainer container, ResourceConfig resourceConfig) {
         super(ApplicationProtocolNames.HTTP_1_1);
 
         this.baseUri = baseUri;
         this.container = container;
+        this.resourceConfig = resourceConfig;
     }
 
     @Override
     protected void configurePipeline(ChannelHandlerContext ctx, String protocol) throws Exception {
         if (ApplicationProtocolNames.HTTP_2.equals(protocol)) {
             ctx.pipeline().addLast(Http2MultiplexCodecBuilder.forServer(
-                        new JerseyHttp2ServerHandler(baseUri, container)).build());
+                        new JerseyHttp2ServerHandler(baseUri, container, resourceConfig)).build());
             return;
         }
 
         if (ApplicationProtocolNames.HTTP_1_1.equals(protocol)) {
             ctx.pipeline().addLast(new HttpServerCodec(),
                                    new ChunkedWriteHandler(),
-                                   new JerseyServerHandler(baseUri, container));
+                                   new JerseyServerHandler(baseUri, container, resourceConfig));
             return;
         }
 
diff --git a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyHttp2ServerHandler.java b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyHttp2ServerHandler.java
index fccb60b..b8da5fe 100644
--- a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyHttp2ServerHandler.java
+++ b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyHttp2ServerHandler.java
@@ -41,6 +41,7 @@
 import org.glassfish.jersey.internal.PropertiesDelegate;
 import org.glassfish.jersey.netty.connector.internal.NettyInputStream;
 import org.glassfish.jersey.server.ContainerRequest;
+import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.server.internal.ContainerUtils;
 
 /**
@@ -56,16 +57,19 @@
     private final URI baseUri;
     private final LinkedBlockingDeque<InputStream> isList = new LinkedBlockingDeque<>();
     private final NettyHttpContainer container;
+    private final ResourceConfig resourceConfig;
 
     /**
      * Constructor.
      *
-     * @param baseUri   base {@link URI} of the container (includes context path, if any).
-     * @param container Netty container implementation.
+     * @param baseUri         base {@link URI} of the container (includes context path, if any).
+     * @param container       Netty container implementation.
+     * @param resourceConfig  the application {@link ResourceConfig}
      */
-    JerseyHttp2ServerHandler(URI baseUri, NettyHttpContainer container) {
+    JerseyHttp2ServerHandler(URI baseUri, NettyHttpContainer container, ResourceConfig resourceConfig) {
         this.baseUri = baseUri;
         this.container = container;
+        this.resourceConfig = resourceConfig;
     }
 
     @Override
@@ -151,7 +155,7 @@
                     public void removeProperty(String name) {
                         properties.remove(name);
                     }
-                });
+                }, resourceConfig);
 
         // request entity handling.
         if (!http2Headers.isEndStream()) {
diff --git a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyServerHandler.java b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyServerHandler.java
index ce033af..06d1782 100644
--- a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyServerHandler.java
+++ b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyServerHandler.java
@@ -19,14 +19,11 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
-import java.security.Principal;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.LinkedBlockingDeque;
 
-import javax.ws.rs.core.SecurityContext;
-
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.ByteBufInputStream;
 import io.netty.channel.ChannelHandlerContext;
@@ -43,8 +40,8 @@
 import io.netty.util.concurrent.GenericFutureListener;
 import org.glassfish.jersey.internal.PropertiesDelegate;
 import org.glassfish.jersey.netty.connector.internal.NettyInputStream;
-import org.glassfish.jersey.netty.httpserver.NettySecurityContext;
 import org.glassfish.jersey.server.ContainerRequest;
+import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.server.internal.ContainerUtils;
 
 /**
@@ -58,16 +55,19 @@
     private final URI baseUri;
     private final LinkedBlockingDeque<InputStream> isList = new LinkedBlockingDeque<>();
     private final NettyHttpContainer container;
+    private final ResourceConfig resourceConfig;
 
     /**
      * Constructor.
      *
      * @param baseUri   base {@link URI} of the container (includes context path, if any).
      * @param container Netty container implementation.
+     * @param resourceConfig  the application {@link ResourceConfig}
      */
-    public JerseyServerHandler(URI baseUri, NettyHttpContainer container) {
+    public JerseyServerHandler(URI baseUri, NettyHttpContainer container, ResourceConfig resourceConfig) {
         this.baseUri = baseUri;
         this.container = container;
+        this.resourceConfig = resourceConfig;
     }
 
     @Override
@@ -146,7 +146,7 @@
                     public void removeProperty(String name) {
                         properties.remove(name);
                     }
-                });
+                }, resourceConfig);
 
         // request entity handling.
         if ((req.headers().contains(HttpHeaderNames.CONTENT_LENGTH) && HttpUtil.getContentLength(req) > 0)
diff --git a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyServerInitializer.java b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyServerInitializer.java
index e7c11bf..d492449 100644
--- a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyServerInitializer.java
+++ b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/JerseyServerInitializer.java
@@ -32,6 +32,7 @@
 import io.netty.handler.ssl.SslContext;
 import io.netty.handler.stream.ChunkedWriteHandler;
 import io.netty.util.AsciiString;
+import org.glassfish.jersey.server.ResourceConfig;
 
 /**
  * Jersey {@link ChannelInitializer}.
@@ -46,30 +47,35 @@
     private final SslContext sslCtx;
     private final NettyHttpContainer container;
     private final boolean http2;
+    private final ResourceConfig resourceConfig;
 
     /**
      * Constructor.
      *
-     * @param baseUri   base {@link URI} of the container (includes context path, if any).
-     * @param sslCtx    SSL context.
-     * @param container Netty container implementation.
+     * @param baseUri         base {@link URI} of the container (includes context path, if any).
+     * @param sslCtx          SSL context.
+     * @param container       Netty container implementation.
+     * @param resourceConfig  the application {@link ResourceConfig}
      */
-    public JerseyServerInitializer(URI baseUri, SslContext sslCtx, NettyHttpContainer container) {
-        this(baseUri, sslCtx, container, false);
+    public JerseyServerInitializer(URI baseUri, SslContext sslCtx, NettyHttpContainer container, ResourceConfig resourceConfig) {
+        this(baseUri, sslCtx, container, resourceConfig, false);
     }
 
     /**
      * Constructor.
      *
-     * @param baseUri   base {@link URI} of the container (includes context path, if any).
-     * @param sslCtx    SSL context.
-     * @param container Netty container implementation.
-     * @param http2     Http/2 protocol support.
+     * @param baseUri         base {@link URI} of the container (includes context path, if any).
+     * @param sslCtx          SSL context.
+     * @param container       Netty container implementation.
+     * @param resourceConfig  the application {@link ResourceConfig}
+     * @param http2           Http/2 protocol support.
      */
-    public JerseyServerInitializer(URI baseUri, SslContext sslCtx, NettyHttpContainer container, boolean http2) {
+    public JerseyServerInitializer(URI baseUri, SslContext sslCtx, NettyHttpContainer container, ResourceConfig resourceConfig,
+                                   boolean http2) {
         this.baseUri = baseUri;
         this.sslCtx = sslCtx;
         this.container = container;
+        this.resourceConfig = resourceConfig;
         this.http2 = http2;
     }
 
@@ -90,7 +96,7 @@
             }
             p.addLast(new HttpServerCodec());
             p.addLast(new ChunkedWriteHandler());
-            p.addLast(new JerseyServerHandler(baseUri, container));
+            p.addLast(new JerseyServerHandler(baseUri, container, resourceConfig));
         }
     }
 
@@ -98,7 +104,7 @@
      * Configure the pipeline for TLS NPN negotiation to HTTP/2.
      */
     private void configureSsl(SocketChannel ch) {
-        ch.pipeline().addLast(sslCtx.newHandler(ch.alloc()), new HttpVersionChooser(baseUri, container));
+        ch.pipeline().addLast(sslCtx.newHandler(ch.alloc()), new HttpVersionChooser(baseUri, container, resourceConfig));
     }
 
     /**
@@ -114,7 +120,7 @@
             public HttpServerUpgradeHandler.UpgradeCodec newUpgradeCodec(CharSequence protocol) {
                 if (AsciiString.contentEquals(Http2CodecUtil.HTTP_UPGRADE_PROTOCOL_NAME, protocol)) {
                     return new Http2ServerUpgradeCodec(Http2MultiplexCodecBuilder.forServer(
-                                new JerseyHttp2ServerHandler(baseUri, container)).build());
+                                new JerseyHttp2ServerHandler(baseUri, container, resourceConfig)).build());
                 } else {
                     return null;
                 }
@@ -128,7 +134,7 @@
 
                 ChannelPipeline pipeline = ctx.pipeline();
                 ChannelHandlerContext thisCtx = pipeline.context(this);
-                pipeline.addAfter(thisCtx.name(), null, new JerseyServerHandler(baseUri, container));
+                pipeline.addAfter(thisCtx.name(), null, new JerseyServerHandler(baseUri, container, resourceConfig));
                 pipeline.replace(this, null, new ChunkedWriteHandler());
                 ctx.fireChannelRead(msg);
             }
diff --git a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpContainerProvider.java b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpContainerProvider.java
index 93981e4..82ab3c1 100644
--- a/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpContainerProvider.java
+++ b/containers/netty-http/src/main/java/org/glassfish/jersey/netty/httpserver/NettyHttpContainerProvider.java
@@ -80,7 +80,7 @@
             b.option(ChannelOption.SO_BACKLOG, 1024);
             b.group(bossGroup, workerGroup)
              .channel(NioServerSocketChannel.class)
-             .childHandler(new JerseyServerInitializer(baseUri, sslContext, container));
+             .childHandler(new JerseyServerInitializer(baseUri, sslContext, container, configuration));
 
             int port = getPort(baseUri);
 
@@ -149,7 +149,7 @@
             b.option(ChannelOption.SO_BACKLOG, 1024);
             b.group(bossGroup, workerGroup)
              .channel(NioServerSocketChannel.class)
-             .childHandler(new JerseyServerInitializer(baseUri, sslContext, container, true));
+             .childHandler(new JerseyServerInitializer(baseUri, sslContext, container, configuration, true));
 
             int port = getPort(baseUri);
 
diff --git a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainer.java b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainer.java
index 22909e1..3561eab 100644
--- a/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainer.java
+++ b/containers/simple-http/src/main/java/org/glassfish/jersey/simple/SimpleContainer.java
@@ -308,7 +308,7 @@
 
         try {
             final ContainerRequest requestContext = new ContainerRequest(baseUri, requestUri,
-                    request.getMethod(), getSecurityContext(request), new MapPropertiesDelegate());
+                    request.getMethod(), getSecurityContext(request), new MapPropertiesDelegate(), appHandler.getConfiguration());
             requestContext.setEntityStream(request.getInputStream());
             for (final String headerName : request.getNames()) {
                 requestContext.headers(headerName, request.getValue(headerName));
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/ClientFilteringStages.java b/core-client/src/main/java/org/glassfish/jersey/client/ClientFilteringStages.java
index 057fac5..672e6bb 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/ClientFilteringStages.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/ClientFilteringStages.java
@@ -92,13 +92,16 @@
                     final Response abortResponse = requestContext.getAbortResponse();
                     if (abortResponse != null) {
                         if (abortResponse.hasEntity() && abortResponse.getMediaType() == null) {
-                            final InboundMessageContext headerContext = new InboundMessageContext() {
+                            final InboundMessageContext headerContext
+                                    = new InboundMessageContext(requestContext.getConfiguration()) {
                                 @Override
                                 protected Iterable<ReaderInterceptor> getReaderInterceptors() {
                                     return null;
                                 }
                             };
-                            headerContext.headers(HeaderUtils.asStringHeaders(abortResponse.getHeaders()));
+                            headerContext.headers(
+                                    HeaderUtils.asStringHeaders(abortResponse.getHeaders(), requestContext.getConfiguration())
+                            );
 
                             final AbortedRequestMediaTypeDeterminer determiner = new AbortedRequestMediaTypeDeterminer(
                                     requestContext.getWorkers());
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/ClientRequest.java b/core-client/src/main/java/org/glassfish/jersey/client/ClientRequest.java
index 22d766d..162deda 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/ClientRequest.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/ClientRequest.java
@@ -94,6 +94,7 @@
      */
     protected ClientRequest(
             final URI requestUri, final ClientConfig clientConfig, final PropertiesDelegate propertiesDelegate) {
+        super(clientConfig.getConfiguration());
         clientConfig.checkClient();
 
         this.requestUri = requestUri;
@@ -273,12 +274,12 @@
 
     @Override
     public List<String> getRequestHeader(String name) {
-        return HeaderUtils.asStringList(getHeaders().get(name), null);
+        return HeaderUtils.asStringList(getHeaders().get(name), clientConfig.getConfiguration());
     }
 
     @Override
     public MultivaluedMap<String, String> getRequestHeaders() {
-        return HeaderUtils.asStringHeaders(getHeaders());
+        return HeaderUtils.asStringHeaders(getHeaders(), clientConfig.getConfiguration());
     }
 
     @Override
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/ClientResponse.java b/core-client/src/main/java/org/glassfish/jersey/client/ClientResponse.java
index 51c9556..2801ed2 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/ClientResponse.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/ClientResponse.java
@@ -63,7 +63,7 @@
      */
     public ClientResponse(final ClientRequest requestContext, final Response response) {
         this(response.getStatusInfo(), requestContext);
-        this.headers(OutboundJaxrsResponse.from(response).getContext().getStringHeaders());
+        this.headers(OutboundJaxrsResponse.from(response, requestContext.getConfiguration()).getContext().getStringHeaders());
 
         final Object entity = response.getEntity();
         if (entity != null) {
@@ -119,6 +119,7 @@
      * @param resolvedRequestUri resolved request URI (see {@link #getResolvedRequestUri()}).
      */
     public ClientResponse(Response.StatusType status, ClientRequest requestContext, URI resolvedRequestUri) {
+        super(requestContext.getConfiguration());
         this.status = status;
         this.resolvedUri = resolvedRequestUri;
         this.requestContext = requestContext;
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/AbstractRuntimeDelegate.java b/core-common/src/main/java/org/glassfish/jersey/internal/AbstractRuntimeDelegate.java
index cc9669e..b488829 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/AbstractRuntimeDelegate.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/AbstractRuntimeDelegate.java
@@ -23,6 +23,7 @@
 import java.util.WeakHashMap;
 
 import javax.ws.rs.core.CacheControl;
+import javax.ws.rs.core.Configuration;
 import javax.ws.rs.core.Cookie;
 import javax.ws.rs.core.EntityTag;
 import javax.ws.rs.core.Link;
@@ -79,7 +80,7 @@
 
     @Override
     public ResponseBuilder createResponseBuilder() {
-        return new OutboundJaxrsResponse.Builder(new OutboundMessageContext());
+        return new OutboundJaxrsResponse.Builder(new OutboundMessageContext((Configuration) null));
     }
 
     @Override
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/AbstractServiceFinderConfigurator.java b/core-common/src/main/java/org/glassfish/jersey/internal/AbstractServiceFinderConfigurator.java
index 2236d63..b835b55 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/AbstractServiceFinderConfigurator.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/AbstractServiceFinderConfigurator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019 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,8 +24,8 @@
 
 import javax.ws.rs.RuntimeType;
 
-import org.glassfish.jersey.CommonProperties;
 import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.util.PropertiesHelper;
 
 /**
  * Simple ServiceFinder configuration.
@@ -59,13 +59,7 @@
      * @return all registered classes of the type {@code T}.
      */
     protected List<Class<T>> loadImplementations(Map<String, Object> applicationProperties) {
-        boolean METAINF_SERVICES_LOOKUP_DISABLE_DEFAULT = false;
-        boolean disableMetaInfServicesLookup = METAINF_SERVICES_LOOKUP_DISABLE_DEFAULT;
-        if (applicationProperties != null) {
-            disableMetaInfServicesLookup = CommonProperties.getValue(applicationProperties, runtimeType,
-                    CommonProperties.METAINF_SERVICES_LOOKUP_DISABLE, METAINF_SERVICES_LOOKUP_DISABLE_DEFAULT, Boolean.class);
-        }
-        if (!disableMetaInfServicesLookup) {
+        if (PropertiesHelper.isMetaInfServicesEnabled(applicationProperties, runtimeType)) {
             return Stream.of(ServiceFinder.find(contract, true).toClassArray())
                     .collect(Collectors.toList());
         }
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateDecorator.java b/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateDecorator.java
new file mode 100644
index 0000000..37b6d93
--- /dev/null
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/RuntimeDelegateDecorator.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2019 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.internal;
+
+import org.glassfish.jersey.internal.util.PropertiesHelper;
+import org.glassfish.jersey.spi.HeaderDelegateProvider;
+
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.Configuration;
+import javax.ws.rs.core.Link;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.Variant;
+import javax.ws.rs.ext.RuntimeDelegate;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * RuntimeDelegate Decorator that changes behaviour due to provided runtime information.
+ * <p/>
+ * Currently the following is possible to be configured based on configurable properties:
+ * <ul>
+ *     <li>{@link org.glassfish.jersey.spi.HeaderDelegateProvider} usage based on
+ *     {@link org.glassfish.jersey.CommonProperties#METAINF_SERVICES_LOOKUP_DISABLE}</li>
+ * </ul>
+ */
+public class RuntimeDelegateDecorator {
+
+    /**
+     * The decorated {@link RuntimeDelegate} that uses {@link HeaderDelegateProvider HeaderDelegateProviders} based on
+     * whether {@link org.glassfish.jersey.CommonProperties#FEATURE_AUTO_DISCOVERY_DISABLE} is set or not
+     *
+     * @param configuration that has or has not {@link org.glassfish.jersey.CommonProperties#FEATURE_AUTO_DISCOVERY_DISABLE} set
+     * @return {@link RuntimeDelegate} that uses {@link HeaderDelegateProvider HeaderDelegateProviders}
+     */
+    public static RuntimeDelegate configured(Configuration configuration) {
+        return new ConfigurableRuntimeDelegate(RuntimeDelegate.getInstance(), configuration);
+    }
+
+    private static class ConfigurableRuntimeDelegate extends RuntimeDelegate {
+
+        private final RuntimeDelegate runtimeDelegate;
+        private final Configuration configuration;
+        private static final Set<HeaderDelegateProvider> headerDelegateProviders;
+
+        private ConfigurableRuntimeDelegate(RuntimeDelegate runtimeDelegate, Configuration configuration) {
+            this.runtimeDelegate = runtimeDelegate;
+            this.configuration = configuration;
+        }
+
+        @Override
+        public UriBuilder createUriBuilder() {
+            return runtimeDelegate.createUriBuilder();
+        }
+
+        @Override
+        public Response.ResponseBuilder createResponseBuilder() {
+            return runtimeDelegate.createResponseBuilder();
+        }
+
+        @Override
+        public Variant.VariantListBuilder createVariantListBuilder() {
+            return runtimeDelegate.createVariantListBuilder();
+        }
+
+        @Override
+        public <T> T createEndpoint(Application application, Class<T> endpointType)
+                throws IllegalArgumentException, UnsupportedOperationException {
+            return runtimeDelegate.createEndpoint(application, endpointType);
+        }
+
+        @Override
+        public <T> RuntimeDelegate.HeaderDelegate<T> createHeaderDelegate(Class<T> type) throws IllegalArgumentException {
+            RuntimeDelegate.HeaderDelegate<T> headerDelegate = null;
+            if (configuration == null
+                    || PropertiesHelper.isMetaInfServicesEnabled(configuration.getProperties(), configuration.getRuntimeType())) {
+                headerDelegate = _createHeaderDelegate(type);
+            }
+            if (headerDelegate == null) {
+                headerDelegate = runtimeDelegate.createHeaderDelegate(type);
+            }
+            return headerDelegate;
+        }
+
+        @Override
+        public Link.Builder createLinkBuilder() {
+            return runtimeDelegate.createLinkBuilder();
+        }
+
+        private <T> HeaderDelegate<T> _createHeaderDelegate(final Class<T> type) {
+            for (final HeaderDelegateProvider hp : headerDelegateProviders) {
+                if (hp.supports(type)) {
+                    return hp;
+                }
+            }
+
+            return null;
+        }
+
+        static {
+            Set<HeaderDelegateProvider> hps = new HashSet<HeaderDelegateProvider>();
+            for (HeaderDelegateProvider provider : ServiceFinder.find(HeaderDelegateProvider.class, true)) {
+                hps.add(provider);
+            }
+            headerDelegateProviders = Collections.unmodifiableSet(hps);
+        }
+    }
+}
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/ServiceFinderBinder.java b/core-common/src/main/java/org/glassfish/jersey/internal/ServiceFinderBinder.java
index 84bf1d4..48b8ebb 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/ServiceFinderBinder.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/ServiceFinderBinder.java
@@ -20,9 +20,9 @@
 
 import javax.ws.rs.RuntimeType;
 
-import org.glassfish.jersey.CommonProperties;
 import org.glassfish.jersey.internal.inject.AbstractBinder;
 import org.glassfish.jersey.internal.inject.InjectionManager;
+import org.glassfish.jersey.internal.util.PropertiesHelper;
 
 /**
  * Simple ServiceFinder injection binder.
@@ -57,13 +57,7 @@
 
     @Override
     protected void configure() {
-        final boolean METAINF_SERVICES_LOOKUP_DISABLE_DEFAULT = false;
-        boolean disableMetainfServicesLookup = METAINF_SERVICES_LOOKUP_DISABLE_DEFAULT;
-        if (applicationProperties != null) {
-            disableMetainfServicesLookup = CommonProperties.getValue(applicationProperties, runtimeType,
-                    CommonProperties.METAINF_SERVICES_LOOKUP_DISABLE, METAINF_SERVICES_LOOKUP_DISABLE_DEFAULT, Boolean.class);
-        }
-        if (!disableMetainfServicesLookup) {
+        if (PropertiesHelper.isMetaInfServicesEnabled(applicationProperties, runtimeType)) {
             for (Class<T> t : ServiceFinder.find(contract, true).toClassArray()) {
                 bind(t).to(contract);
             }
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/util/PropertiesHelper.java b/core-common/src/main/java/org/glassfish/jersey/internal/util/PropertiesHelper.java
index ee292cf..dcea2d3 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/util/PropertiesHelper.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/util/PropertiesHelper.java
@@ -28,6 +28,7 @@
 
 import javax.ws.rs.RuntimeType;
 
+import org.glassfish.jersey.CommonProperties;
 import org.glassfish.jersey.internal.LocalizationMessages;
 
 /**
@@ -39,6 +40,7 @@
 public final class PropertiesHelper {
 
     private static final Logger LOGGER = Logger.getLogger(PropertiesHelper.class.getName());
+    private static final boolean METAINF_SERVICES_LOOKUP_DISABLE_DEFAULT = false;
 
     /**
      * Get system properties.
@@ -315,6 +317,23 @@
     }
 
     /**
+     * Determine whether {@link CommonProperties#METAINF_SERVICES_LOOKUP_DISABLE} does not globally
+     * disable META-INF/services lookup on client/server.
+     *
+     * @param properties  map containing application properties. May be {@code null}
+     * @param runtimeType runtime (client or server) where the service finder binder is used.
+     * @return {@code true} if the {@link CommonProperties#METAINF_SERVICES_LOOKUP_DISABLE} is not se to true
+     */
+    public static boolean isMetaInfServicesEnabled(Map<String, Object> properties, RuntimeType runtimeType) {
+        boolean disableMetaInfServicesLookup = METAINF_SERVICES_LOOKUP_DISABLE_DEFAULT;
+        if (properties != null) {
+            disableMetaInfServicesLookup = CommonProperties.getValue(properties, runtimeType,
+                    CommonProperties.METAINF_SERVICES_LOOKUP_DISABLE, METAINF_SERVICES_LOOKUP_DISABLE_DEFAULT, Boolean.class);
+        }
+        return !disableMetaInfServicesLookup;
+    }
+
+    /**
      * Get the value of the property with a given name converted to {@code boolean}. Returns {@code false} if the value is
      * not convertible.
      *
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/HeaderUtils.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/HeaderUtils.java
index 1bf5440..4500ea9 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/HeaderUtils.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/HeaderUtils.java
@@ -27,10 +27,12 @@
 import java.util.stream.Collectors;
 
 import javax.ws.rs.core.AbstractMultivaluedMap;
+import javax.ws.rs.core.Configuration;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.ext.RuntimeDelegate;
 import javax.ws.rs.ext.RuntimeDelegate.HeaderDelegate;
 
+import org.glassfish.jersey.internal.RuntimeDelegateDecorator;
 import org.glassfish.jersey.internal.LocalizationMessages;
 import org.glassfish.jersey.internal.util.collection.ImmutableMultivaluedMap;
 import org.glassfish.jersey.internal.util.collection.StringKeyIgnoreCaseMultivaluedMap;
@@ -84,8 +86,9 @@
      * this method returns {@code null}.
      * <p>
      * This method defers to {@link RuntimeDelegate#createHeaderDelegate} to
-     * obtain a {@link HeaderDelegate} to convert the value to a {@code String}.
-     * If a {@link HeaderDelegate} is not found then the {@code toString()}
+     * obtain a {@link HeaderDelegate} or {@link org.glassfish.jersey.spi.HeaderDelegateProvider}
+     * to convert the value to a {@code String}.
+     * If neither is found then the {@code toString()}
      * method on the header object is utilized.
      *
      * @param headerValue the header value represented as an object.
@@ -97,7 +100,7 @@
      *         if the supplied header value is {@code null}.
      */
     @SuppressWarnings("unchecked")
-    public static String asString(final Object headerValue, RuntimeDelegate rd) {
+    private static String asString(final Object headerValue, RuntimeDelegate rd) {
         if (headerValue == null) {
             return null;
         }
@@ -113,6 +116,29 @@
     }
 
     /**
+     * Convert a message header value, represented as a general object, to it's
+     * string representation. If the supplied header value is {@code null},
+     * this method returns {@code null}.
+     * <p>
+     * This method defers to {@link RuntimeDelegate#createHeaderDelegate} to
+     * obtain a {@link HeaderDelegate} or {@link org.glassfish.jersey.spi.HeaderDelegateProvider}
+     * to convert the value to a {@code String}.
+     * If neither is found then the {@code toString()}
+     * method on the header object is utilized.
+     *
+     * @param headerValue   the header value represented as an object.
+     * @param configuration the {@link Configuration} that may contain
+     *                      {@link org.glassfish.jersey.CommonProperties#METAINF_SERVICES_LOOKUP_DISABLE}
+     *                      property preventing the {@link org.glassfish.jersey.spi.HeaderDelegateProvider}
+     *                      to be used by the default {@code RuntimeDelegate} {@link RuntimeDelegate#getInstance() instance}.
+     * @return the string representation of the supplied header value or {@code null}
+     *         if the supplied header value is {@code null}.
+     */
+    public static String asString(final Object headerValue, Configuration configuration) {
+        return asString(headerValue, RuntimeDelegateDecorator.configured(configuration));
+    }
+
+    /**
      * Returns string view of list of header values. Any modifications to the underlying list are visible to the view,
      * the view also supports removal of elements. Does not support other modifications.
      *
@@ -121,21 +147,29 @@
      *                     will be called for before element conversion.
      * @return String view of header values.
      */
-    public static List<String> asStringList(final List<Object> headerValues, final RuntimeDelegate rd) {
+    private static List<String> asStringList(final List<Object> headerValues, final RuntimeDelegate rd) {
         if (headerValues == null || headerValues.isEmpty()) {
             return Collections.emptyList();
         }
 
-        final RuntimeDelegate delegate;
-        if (rd == null) {
-            delegate = RuntimeDelegate.getInstance();
-        } else {
-            delegate = rd;
-        }
-
         return Views.listView(headerValues, input -> (input == null)
                 ? "[null]"
-                : HeaderUtils.asString(input, delegate));
+                : HeaderUtils.asString(input, rd));
+    }
+
+    /**
+     * Returns string view of list of header values. Any modifications to the underlying list are visible to the view,
+     * the view also supports removal of elements. Does not support other modifications.
+     *
+     * @param headerValues header values.
+     * @param configuration the {@link Configuration} that may contain
+     *                      {@link org.glassfish.jersey.CommonProperties#METAINF_SERVICES_LOOKUP_DISABLE}
+     *                      property preventing the {@link org.glassfish.jersey.spi.HeaderDelegateProvider}
+     *                      to be used by the default {@code RuntimeDelegate} {@link RuntimeDelegate#getInstance() instance}.
+     * @return String view of header values.
+     */
+    public static List<String> asStringList(final List<Object> headerValues, final Configuration configuration) {
+        return asStringList(headerValues, RuntimeDelegateDecorator.configured(configuration));
     }
 
     /**
@@ -143,14 +177,19 @@
      * supports removal of elements. Does not support other modifications.
      *
      * @param headers headers.
+     * @param configuration the {@link Configuration} that may contain
+     *                      {@link org.glassfish.jersey.CommonProperties#METAINF_SERVICES_LOOKUP_DISABLE}
+     *                      property preventing the {@link org.glassfish.jersey.spi.HeaderDelegateProvider}
+     *                      to be used by the default {@code RuntimeDelegate} {@link RuntimeDelegate#getInstance() instance}.
      * @return String view of headers or {@code null} if {code headers} input parameter is {@code null}.
      */
-    public static MultivaluedMap<String, String> asStringHeaders(final MultivaluedMap<String, Object> headers) {
+    public static MultivaluedMap<String, String> asStringHeaders(
+            final MultivaluedMap<String, Object> headers, Configuration configuration) {
         if (headers == null) {
             return null;
         }
 
-        final RuntimeDelegate rd = RuntimeDelegate.getInstance();
+        final RuntimeDelegate rd = RuntimeDelegateDecorator.configured(configuration);
         return new AbstractMultivaluedMap<String, String>(
                 Views.mapView(headers, input -> HeaderUtils.asStringList(input, rd))
         ) {
@@ -163,16 +202,20 @@
      * Returned map is immutable. Map values are formatted using method {@link #asHeaderString}.
      *
      * @param headers headers to be formatted
+     * @param configuration the {@link Configuration} that may contain
+     *                      {@link org.glassfish.jersey.CommonProperties#METAINF_SERVICES_LOOKUP_DISABLE}
+     *                      property preventing the {@link org.glassfish.jersey.spi.HeaderDelegateProvider}
+     *                      to be used by the default {@code RuntimeDelegate} {@link RuntimeDelegate#getInstance() instance}.
      * @return immutable single {@code String} value map or
      *      {@code null} if {@code headers} input parameter is {@code null}.
      */
-    public static Map<String, String> asStringHeadersSingleValue(final MultivaluedMap<String, Object> headers) {
+    public static Map<String, String> asStringHeadersSingleValue(
+            final MultivaluedMap<String, Object> headers, Configuration configuration) {
         if (headers == null) {
             return null;
         }
 
-        final RuntimeDelegate rd = RuntimeDelegate.getInstance();
-
+        final RuntimeDelegate rd = RuntimeDelegateDecorator.configured(configuration);
         return Collections.unmodifiableMap(headers.entrySet().stream()
                                            .collect(Collectors.toMap(
                                                    Map.Entry::getKey,
@@ -222,13 +265,18 @@
      * @param headersSnapshot first immutable snapshot of headers
      * @param currentHeaders  current instance of headers tobe compared to
      * @param connectorName   name of connector the method is invoked from, used just in logged message
+     * @param configuration the {@link Configuration} that may contain
+     *                      {@link org.glassfish.jersey.CommonProperties#METAINF_SERVICES_LOOKUP_DISABLE}
+     *                      property preventing the {@link org.glassfish.jersey.spi.HeaderDelegateProvider}
+     *                      to be used by the default {@code RuntimeDelegate} {@link RuntimeDelegate#getInstance() instance}.
      * @see <a href="https://java.net/jira/browse/JERSEY-2341">JERSEY-2341</a>
      */
     public static void checkHeaderChanges(final Map<String, String> headersSnapshot,
                                           final MultivaluedMap<String, Object> currentHeaders,
-                                          final String connectorName) {
+                                          final String connectorName,
+                                          final Configuration configuration) {
         if (HeaderUtils.LOGGER.isLoggable(Level.WARNING)) {
-            final RuntimeDelegate rd = RuntimeDelegate.getInstance();
+            final RuntimeDelegate rd = RuntimeDelegateDecorator.configured(configuration);
             final Set<String> changedHeaderNames = new HashSet<String>();
             for (final Map.Entry<? extends String, ? extends List<Object>> entry : currentHeaders.entrySet()) {
                 if (!headersSnapshot.containsKey(entry.getKey())) {
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/InboundMessageContext.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/InboundMessageContext.java
index a8ba51c..e150624 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/InboundMessageContext.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/InboundMessageContext.java
@@ -40,6 +40,7 @@
 import java.util.function.Function;
 
 import javax.ws.rs.ProcessingException;
+import javax.ws.rs.core.Configuration;
 import javax.ws.rs.core.Cookie;
 import javax.ws.rs.core.EntityTag;
 import javax.ws.rs.core.HttpHeaders;
@@ -48,7 +49,6 @@
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.NewCookie;
 import javax.ws.rs.ext.ReaderInterceptor;
-import javax.ws.rs.ext.RuntimeDelegate;
 
 import javax.xml.transform.Source;
 
@@ -93,6 +93,7 @@
     private final EntityContent entityContent;
     private final boolean translateNce;
     private MessageBodyWorkers workers;
+    private final Configuration configuration;
 
     /**
      * Input stream and its state. State is represented by the {@link Type Type enum} and
@@ -139,22 +140,27 @@
 
     /**
      * Create new inbound message context.
+     *
+     * @param configuration the related client/server side {@link Configuration}
      */
-    public InboundMessageContext() {
-        this(false);
+    public InboundMessageContext(Configuration configuration) {
+        this(configuration, false);
     }
 
     /**
      * Create new inbound message context.
      *
-     * @param translateNce if {@code true}, the {@link javax.ws.rs.core.NoContentException} thrown by a
-     *                     selected message body reader will be translated into a {@link javax.ws.rs.BadRequestException}
-     *                     as required by JAX-RS specification on the server side.
+     * @param configuration the related client/server side {@link Configuration}. If {@code null},
+     *                      the default behaviour is expected.
+     * @param translateNce  if {@code true}, the {@link javax.ws.rs.core.NoContentException} thrown by a
+     *                      selected message body reader will be translated into a {@link javax.ws.rs.BadRequestException}
+     *                      as required by JAX-RS specification on the server side.
      */
-    public InboundMessageContext(boolean translateNce) {
+    public InboundMessageContext(Configuration configuration, boolean translateNce) {
         this.headers = HeaderUtils.createInbound();
         this.entityContent = new EntityContent();
         this.translateNce = translateNce;
+        this.configuration = configuration;
     }
 
     // Message headers
@@ -167,7 +173,7 @@
      * @return updated context.
      */
     public InboundMessageContext header(String name, Object value) {
-        getHeaders().add(name, HeaderUtils.asString(value, RuntimeDelegate.getInstance()));
+        getHeaders().add(name, HeaderUtils.asString(value, configuration));
         return this;
     }
 
@@ -179,7 +185,7 @@
      * @return updated context.
      */
     public InboundMessageContext headers(String name, Object... values) {
-        this.getHeaders().addAll(name, HeaderUtils.asStringList(Arrays.asList(values), RuntimeDelegate.getInstance()));
+        this.getHeaders().addAll(name, HeaderUtils.asStringList(Arrays.asList(values), configuration));
         return this;
     }
 
@@ -232,12 +238,11 @@
         return this;
     }
 
-    private static List<String> iterableToList(final Iterable<?> values) {
+    private List<String> iterableToList(final Iterable<?> values) {
         final LinkedList<String> linkedList = new LinkedList<String>();
 
-        final RuntimeDelegate rd = RuntimeDelegate.getInstance();
         for (Object element : values) {
-            linkedList.add(HeaderUtils.asString(element, rd));
+            linkedList.add(HeaderUtils.asString(element, configuration));
         }
 
         return linkedList;
@@ -924,4 +929,12 @@
      * @return reader interceptors bound to this context.
      */
     protected abstract Iterable<ReaderInterceptor> getReaderInterceptors();
+
+    /**
+     * The related client/server side {@link Configuration}. Can be {@code null}.
+     * @return {@link Configuration} the configuration
+     */
+    public Configuration getConfiguration() {
+        return configuration;
+    }
 }
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundJaxrsResponse.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundJaxrsResponse.java
index 27843db..508521f 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundJaxrsResponse.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundJaxrsResponse.java
@@ -32,6 +32,7 @@
 
 import javax.ws.rs.ProcessingException;
 import javax.ws.rs.core.CacheControl;
+import javax.ws.rs.core.Configuration;
 import javax.ws.rs.core.EntityTag;
 import javax.ws.rs.core.GenericType;
 import javax.ws.rs.core.HttpHeaders;
@@ -39,6 +40,7 @@
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.NewCookie;
+import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Variant;
 
 import org.glassfish.jersey.internal.LocalizationMessages;
@@ -63,14 +65,17 @@
      * Get an OutboundJaxrsResponse instance for a given JAX-RS response.
      *
      * @param response response instance to from.
+     * @param configuration the related client/server side {@link Configuration}. Can be {@code null}.
      * @return corresponding {@code OutboundJaxrsResponse} instance.
      */
-    public static OutboundJaxrsResponse from(javax.ws.rs.core.Response response) {
+    public static OutboundJaxrsResponse from(Response response, Configuration configuration) {
         if (response instanceof OutboundJaxrsResponse) {
+             // RuntimeDelegate.getInstance().createResponseBuilder() does not set configuration
+            ((OutboundJaxrsResponse) response).context.setConfiguration(configuration);
             return (OutboundJaxrsResponse) response;
         } else {
             final StatusType status = response.getStatusInfo();
-            final OutboundMessageContext context = new OutboundMessageContext();
+            final OutboundMessageContext context = new OutboundMessageContext(configuration);
             context.getHeaders().putAll(response.getMetadata());
             context.setEntity(response.getEntity());
             return new OutboundJaxrsResponse(status, context);
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundMessageContext.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundMessageContext.java
index ef37b6c..a33d345 100644
--- a/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundMessageContext.java
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/OutboundMessageContext.java
@@ -47,9 +47,9 @@
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.NewCookie;
-import javax.ws.rs.ext.RuntimeDelegate;
 
 import org.glassfish.jersey.CommonProperties;
+import org.glassfish.jersey.internal.RuntimeDelegateDecorator;
 import org.glassfish.jersey.internal.LocalizationMessages;
 import org.glassfish.jersey.internal.util.ReflectionHelper;
 
@@ -65,6 +65,7 @@
 
     private final MultivaluedMap<String, Object> headers;
     private final CommittingOutputStream committingOutputStream;
+    private Configuration configuration;
 
     private Object entity;
     private GenericType<?> entityType;
@@ -72,6 +73,7 @@
     private OutputStream entityStream;
 
 
+
     /**
      * The callback interface which is used to get the terminal output stream into which the entity should be
      * written and to inform the implementation about the entity size.
@@ -95,8 +97,10 @@
 
     /**
      * Create new outbound message context.
+     * @param configuration the client/server {@link Configuration}. If {@code null}, the default behaviour is expected.
      */
-    public OutboundMessageContext() {
+    public OutboundMessageContext(Configuration configuration) {
+        this.configuration = configuration;
         this.headers = HeaderUtils.createOutbound();
         this.committingOutputStream = new CommittingOutputStream();
         this.entityStream = committingOutputStream;
@@ -117,6 +121,7 @@
         this.entity = original.entity;
         this.entityType = original.entityType;
         this.entityAnnotations = original.entityAnnotations;
+        this.configuration = original.configuration;
     }
 
     /**
@@ -138,7 +143,7 @@
      * @return multi-valued map of outbound message header names to their string-converted values.
      */
     public MultivaluedMap<String, String> getStringHeaders() {
-        return HeaderUtils.asStringHeaders(headers);
+        return HeaderUtils.asStringHeaders(headers, configuration);
     }
 
     /**
@@ -158,7 +163,7 @@
      * character.
      */
     public String getHeaderString(String name) {
-        return HeaderUtils.asHeaderString(headers.get(name), RuntimeDelegate.getInstance());
+        return HeaderUtils.asHeaderString(headers.get(name), RuntimeDelegateDecorator.configured(configuration));
     }
 
     /**
@@ -269,7 +274,6 @@
             return WILDCARD_ACCEPTABLE_TYPE_SINGLETON_LIST;
         }
         final List<MediaType> result = new ArrayList<>(values.size());
-        final RuntimeDelegate rd = RuntimeDelegate.getInstance();
         boolean conversionApplied = false;
         for (final Object value : values) {
             try {
@@ -279,7 +283,7 @@
                     result.add(_value);
                 } else {
                     conversionApplied = true;
-                    result.addAll(HttpHeaderReader.readAcceptMediaType(HeaderUtils.asString(value, rd)));
+                    result.addAll(HttpHeaderReader.readAcceptMediaType(HeaderUtils.asString(value, configuration)));
                 }
             } catch (java.text.ParseException e) {
                 throw exception(HttpHeaders.ACCEPT, value, e);
@@ -311,7 +315,6 @@
         }
 
         final List<Locale> result = new ArrayList<Locale>(values.size());
-        final RuntimeDelegate rd = RuntimeDelegate.getInstance();
         boolean conversionApplied = false;
         for (final Object value : values) {
             if (value instanceof Locale) {
@@ -319,7 +322,7 @@
             } else {
                 conversionApplied = true;
                 try {
-                    result.addAll(HttpHeaderReader.readAcceptLanguage(HeaderUtils.asString(value, rd))
+                    result.addAll(HttpHeaderReader.readAcceptLanguage(HeaderUtils.asString(value, configuration))
                                                   .stream()
                                                   .map(LanguageTag::getAsLocale)
                                                   .collect(Collectors.toList()));
@@ -352,7 +355,7 @@
         }
 
         Map<String, Cookie> result = new HashMap<String, Cookie>();
-        for (String cookie : HeaderUtils.asStringList(cookies, RuntimeDelegate.getInstance())) {
+        for (String cookie : HeaderUtils.asStringList(cookies, configuration)) {
             if (cookie != null) {
                 result.putAll(HttpHeaderReader.readCookies(cookie));
             }
@@ -440,7 +443,7 @@
         }
 
         Map<String, NewCookie> result = new HashMap<String, NewCookie>();
-        for (String cookie : HeaderUtils.asStringList(cookies, RuntimeDelegate.getInstance())) {
+        for (String cookie : HeaderUtils.asStringList(cookies, configuration)) {
             if (cookie != null) {
                 NewCookie newCookie = HttpHeaderReader.readNewCookie(cookie);
                 result.put(newCookie.getName(), newCookie);
@@ -516,7 +519,6 @@
         }
 
         final Set<Link> result = new HashSet<Link>(values.size());
-        final RuntimeDelegate rd = RuntimeDelegate.getInstance();
         boolean conversionApplied = false;
         for (final Object value : values) {
             if (value instanceof Link) {
@@ -524,7 +526,7 @@
             } else {
                 conversionApplied = true;
                 try {
-                    result.add(Link.valueOf(HeaderUtils.asString(value, rd)));
+                    result.add(Link.valueOf(HeaderUtils.asString(value, configuration)));
                 } catch (IllegalArgumentException e) {
                     throw exception(HttpHeaders.LINK, value, e);
                 }
@@ -842,4 +844,16 @@
             }
         }
     }
+
+    void setConfiguration(Configuration configuration) {
+        this.configuration = configuration;
+    }
+
+    /**
+     * The related client/server side {@link Configuration}. Can be {@code null}.
+     * @return {@link Configuration} the configuration
+     */
+    public Configuration getConfiguration() {
+        return configuration;
+    }
 }
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ContainerRequest.java b/core-server/src/main/java/org/glassfish/jersey/server/ContainerRequest.java
index 21459fa..c1bfaa6 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/ContainerRequest.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/ContainerRequest.java
@@ -34,6 +34,7 @@
 import javax.ws.rs.container.ContainerRequestContext;
 import javax.ws.rs.container.ContainerRequestFilter;
 import javax.ws.rs.container.ContainerResponseFilter;
+import javax.ws.rs.core.Configuration;
 import javax.ws.rs.core.Cookie;
 import javax.ws.rs.core.EntityTag;
 import javax.ws.rs.core.HttpHeaders;
@@ -139,14 +140,16 @@
      *                           by the container.
      * @param propertiesDelegate custom {@link PropertiesDelegate properties delegate}
      *                           to be used by the context.
+     * @param configuration the server {@link Configuration}. If {@code null}, the default behaviour is expected.
      */
     public ContainerRequest(
             final URI baseUri,
             final URI requestUri,
             final String httpMethod,
             final SecurityContext securityContext,
-            final PropertiesDelegate propertiesDelegate) {
-        super(true);
+            final PropertiesDelegate propertiesDelegate,
+            final Configuration configuration) {
+        super(configuration, true);
 
         this.baseUri = baseUri == null ? DEFAULT_BASE_URI : baseUri.normalize();
         this.requestUri = requestUri;
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ContainerResponse.java b/core-server/src/main/java/org/glassfish/jersey/server/ContainerResponse.java
index 90b3bda..36af408 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/ContainerResponse.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/ContainerResponse.java
@@ -62,7 +62,7 @@
      * @param response response instance initializing the response context.
      */
     public ContainerResponse(final ContainerRequest requestContext, final Response response) {
-        this(requestContext, OutboundJaxrsResponse.from(response));
+        this(requestContext, OutboundJaxrsResponse.from(response, requestContext.getConfiguration()));
     }
 
     /**
diff --git a/core-server/src/test/java/org/glassfish/jersey/server/ContainerRequestTest.java b/core-server/src/test/java/org/glassfish/jersey/server/ContainerRequestTest.java
index f2cb244..7a479e0 100644
--- a/core-server/src/test/java/org/glassfish/jersey/server/ContainerRequestTest.java
+++ b/core-server/src/test/java/org/glassfish/jersey/server/ContainerRequestTest.java
@@ -72,7 +72,7 @@
     public void testAcceptableMediaTypes() throws URISyntaxException {
         ContainerRequest r = new ContainerRequest(
                 URI.create("http://example.org/app"), URI.create("http://example.org/app/resource"),
-                "GET", SECURITY_CONTEXT, new MapPropertiesDelegate());
+                "GET", SECURITY_CONTEXT, new MapPropertiesDelegate(), null);
         r.header(HttpHeaders.ACCEPT, "application/xml, text/plain");
         r.header(HttpHeaders.ACCEPT, "application/json");
         assertEquals(r.getAcceptableMediaTypes().size(), 3);
@@ -85,7 +85,7 @@
     public void testAcceptableLanguages() throws URISyntaxException {
         ContainerRequest r = new ContainerRequest(
                 URI.create("http://example.org/app"), URI.create("http://example.org/app/resource"),
-                "GET", SECURITY_CONTEXT, new MapPropertiesDelegate());
+                "GET", SECURITY_CONTEXT, new MapPropertiesDelegate(), null);
         r.header(HttpHeaders.ACCEPT_LANGUAGE, "en-gb;q=0.8, en;q=0.7");
         r.header(HttpHeaders.ACCEPT_LANGUAGE, "de");
         assertEquals(r.getAcceptableLanguages().size(), 3);
@@ -98,7 +98,7 @@
     public void testMethod() {
         ContainerRequest r = new ContainerRequest(
                 URI.create("http://example.org/app"), URI.create("http://example.org/app/resource"),
-                "GET", SECURITY_CONTEXT, new MapPropertiesDelegate());
+                "GET", SECURITY_CONTEXT, new MapPropertiesDelegate(), null);
         assertEquals(r.getMethod(), "GET");
     }
 
@@ -106,7 +106,7 @@
     public void testUri() throws URISyntaxException {
         ContainerRequest r = new ContainerRequest(
                 URI.create("http://example.org/app"), URI.create("http://example.org/app/resource"),
-                "GET", SECURITY_CONTEXT, new MapPropertiesDelegate());
+                "GET", SECURITY_CONTEXT, new MapPropertiesDelegate(), null);
         assertEquals(r.getRequestUri(), URI.create("http://example.org/app/resource"));
     }
 
@@ -114,7 +114,7 @@
     public void testSelectVariant() {
         ContainerRequest r = new ContainerRequest(
                 URI.create("http://example.org/app"), URI.create("http://example.org/app/resource"),
-                "GET", SECURITY_CONTEXT, new MapPropertiesDelegate());
+                "GET", SECURITY_CONTEXT, new MapPropertiesDelegate(), null);
         r.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON);
         r.header(HttpHeaders.ACCEPT_LANGUAGE, "en");
         List<Variant> lv = Variant
@@ -129,7 +129,7 @@
     public void testPreconditionsMatch() {
         ContainerRequest r = new ContainerRequest(
                 URI.create("http://example.org/app"), URI.create("http://example.org/app/resource"),
-                "GET", SECURITY_CONTEXT, new MapPropertiesDelegate());
+                "GET", SECURITY_CONTEXT, new MapPropertiesDelegate(), null);
         r.header(HttpHeaders.IF_MATCH, "\"686897696a7c876b7e\"");
         assertNull(r.evaluatePreconditions(new EntityTag("686897696a7c876b7e")));
         assertEquals(r.evaluatePreconditions(new EntityTag("0")).build().getStatus(),
@@ -140,7 +140,7 @@
     public void testPreconditionsNoneMatch() {
         ContainerRequest r = new ContainerRequest(
                 URI.create("http://example.org/app"), URI.create("http://example.org/app/resource"),
-                "GET", SECURITY_CONTEXT, new MapPropertiesDelegate());
+                "GET", SECURITY_CONTEXT, new MapPropertiesDelegate(), null);
         r.header(HttpHeaders.IF_NONE_MATCH, "\"686897696a7c876b7e\"");
         assertEquals(r.evaluatePreconditions(new EntityTag("686897696a7c876b7e")).build().getStatus(),
                 Response.Status.NOT_MODIFIED.getStatusCode());
@@ -151,7 +151,7 @@
     public void testPreconditionsModified() throws ParseException {
         ContainerRequest r = new ContainerRequest(
                 URI.create("http://example.org/app"), URI.create("http://example.org/app/resource"),
-                "GET", SECURITY_CONTEXT, new MapPropertiesDelegate());
+                "GET", SECURITY_CONTEXT, new MapPropertiesDelegate(), null);
         r.header(HttpHeaders.IF_MODIFIED_SINCE, "Sat, 29 Oct 2011 19:43:31 GMT");
         SimpleDateFormat f = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss Z", Locale.ENGLISH);
         Date date = f.parse("Sat, 29 Oct 2011 19:43:31 GMT");
@@ -165,7 +165,7 @@
     public void testPreconditionsUnModified() throws ParseException {
         ContainerRequest r = new ContainerRequest(
                 URI.create("http://example.org/app"), URI.create("http://example.org/app/resource"),
-                "GET", SECURITY_CONTEXT, new MapPropertiesDelegate());
+                "GET", SECURITY_CONTEXT, new MapPropertiesDelegate(), null);
         r.header(HttpHeaders.IF_UNMODIFIED_SINCE, "Sat, 29 Oct 2011 19:43:31 GMT");
         SimpleDateFormat f = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss Z", Locale.ENGLISH);
         Date date = f.parse("Sat, 29 Oct 2011 19:43:31 GMT");
@@ -177,7 +177,8 @@
 
     private ContainerRequest getContainerRequestForPreconditionsTest() {
         return new ContainerRequest(URI.create("http://example.org"),
-                    URI.create("http://example.org/app/respource"), "GET", SECURITY_CONTEXT, new MapPropertiesDelegate());
+                URI.create("http://example.org/app/respource"), "GET", SECURITY_CONTEXT,
+                new MapPropertiesDelegate(), null);
     }
 
     @Test(expected = IllegalArgumentException.class)
diff --git a/core-server/src/test/java/org/glassfish/jersey/server/RequestContextBuilder.java b/core-server/src/test/java/org/glassfish/jersey/server/RequestContextBuilder.java
index 4209407..6f4a38a 100644
--- a/core-server/src/test/java/org/glassfish/jersey/server/RequestContextBuilder.java
+++ b/core-server/src/test/java/org/glassfish/jersey/server/RequestContextBuilder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019 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
@@ -36,7 +36,6 @@
 import javax.ws.rs.core.MultivaluedHashMap;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.SecurityContext;
-import javax.ws.rs.ext.RuntimeDelegate;
 import javax.ws.rs.ext.WriterInterceptor;
 
 import org.glassfish.jersey.internal.MapPropertiesDelegate;
@@ -62,7 +61,7 @@
                                     final String method,
                                     final SecurityContext securityContext,
                                     final PropertiesDelegate propertiesDelegate) {
-            super(baseUri, requestUri, method, securityContext, propertiesDelegate);
+            super(baseUri, requestUri, method, securityContext, propertiesDelegate, null);
             this.propertiesDelegate = propertiesDelegate;
         }
 
@@ -108,7 +107,6 @@
         }
     }
 
-    private final RuntimeDelegate delegate = RuntimeDelegate.getInstance();
     private final TestContainerRequest request;
 
     public static RequestContextBuilder from(final String requestUri, final String method) {
@@ -132,8 +130,7 @@
     }
 
     private RequestContextBuilder(final URI baseUri, final URI requestUri, final String method) {
-        request = new TestContainerRequest(baseUri, requestUri, method, null,
-                new MapPropertiesDelegate());
+        request = new TestContainerRequest(baseUri, requestUri, method, null, new MapPropertiesDelegate());
     }
 
     public ContainerRequest build() {
@@ -162,7 +159,7 @@
     }
 
     public RequestContextBuilder type(final MediaType contentType) {
-        request.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE, HeaderUtils.asString(contentType, delegate));
+        request.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE, HeaderUtils.asString(contentType, null));
         return this;
     }
 
@@ -186,7 +183,7 @@
             request.getHeaders().remove(name);
             return;
         }
-        request.header(name, HeaderUtils.asString(value, delegate));
+        request.header(name, HeaderUtils.asString(value, null));
     }
 
     private void putHeaders(final String name, final Object... values) {
@@ -194,7 +191,7 @@
             request.getHeaders().remove(name);
             return;
         }
-        request.getHeaders().addAll(name, HeaderUtils.asStringList(Arrays.asList(values), delegate));
+        request.getHeaders().addAll(name, HeaderUtils.asStringList(Arrays.asList(values), null));
     }
 
     private void putHeaders(final String name, final String... values) {
diff --git a/examples/helloworld-benchmark/src/main/java/org/glassfish/jersey/examples/helloworld/HelloWorldBenchmark.java b/examples/helloworld-benchmark/src/main/java/org/glassfish/jersey/examples/helloworld/HelloWorldBenchmark.java
index 89c6365..db1ef85 100644
--- a/examples/helloworld-benchmark/src/main/java/org/glassfish/jersey/examples/helloworld/HelloWorldBenchmark.java
+++ b/examples/helloworld-benchmark/src/main/java/org/glassfish/jersey/examples/helloworld/HelloWorldBenchmark.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Distribution License v. 1.0, which is available at
@@ -65,7 +65,7 @@
     @Setup(Level.Iteration)
     public void request() {
         request = ContainerRequestBuilder
-                .from(path, method)
+                .from(path, method, handler.getConfiguration())
                 .entity("GET".equals(method) ? null : HelloWorldResource.CLICHED_MESSAGE, handler)
                 .build();
     }
diff --git a/media/json-processing/src/test/java/org/glassfish/jersey/jsonp/JsonProcessingAutoDiscoverableServerTest.java b/media/json-processing/src/test/java/org/glassfish/jersey/jsonp/JsonProcessingAutoDiscoverableServerTest.java
index 80f2485..58da0e1 100644
--- a/media/json-processing/src/test/java/org/glassfish/jersey/jsonp/JsonProcessingAutoDiscoverableServerTest.java
+++ b/media/json-processing/src/test/java/org/glassfish/jersey/jsonp/JsonProcessingAutoDiscoverableServerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019 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
@@ -126,7 +126,8 @@
         final ApplicationHandler app = new ApplicationHandler(resourceConfig);
 
         final URI baseUri = URI.create("/");
-        assertEquals(response, app.apply(new ContainerRequest(baseUri, baseUri, "GET", null, new MapPropertiesDelegate())).get()
+        assertEquals(response, app.apply(new ContainerRequest(baseUri, baseUri, "GET", null,
+                new MapPropertiesDelegate(), resourceConfig)).get()
                 .getEntity());
     }
 }
diff --git a/test-framework/providers/inmemory/src/main/java/org/glassfish/jersey/test/inmemory/InMemoryConnector.java b/test-framework/providers/inmemory/src/main/java/org/glassfish/jersey/test/inmemory/InMemoryConnector.java
index 971790a..0ed0987 100644
--- a/test-framework/providers/inmemory/src/main/java/org/glassfish/jersey/test/inmemory/InMemoryConnector.java
+++ b/test-framework/providers/inmemory/src/main/java/org/glassfish/jersey/test/inmemory/InMemoryConnector.java
@@ -193,7 +193,7 @@
 
         final ContainerRequest containerRequest = new ContainerRequest(baseUri,
                 clientRequest.getUri(), clientRequest.getMethod(),
-                null, propertiesDelegate);
+                null, propertiesDelegate, appHandler.getConfiguration());
 
         containerRequest.getHeaders().putAll(clientRequest.getStringHeaders());
 
diff --git a/test-framework/util/src/main/java/org/glassfish/jersey/test/util/client/LoopBackConnector.java b/test-framework/util/src/main/java/org/glassfish/jersey/test/util/client/LoopBackConnector.java
index 5dafe53..794db73 100644
--- a/test-framework/util/src/main/java/org/glassfish/jersey/test/util/client/LoopBackConnector.java
+++ b/test-framework/util/src/main/java/org/glassfish/jersey/test/util/client/LoopBackConnector.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019 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
@@ -93,7 +93,7 @@
         final ClientResponse response = new ClientResponse(LOOPBACK_STATUS, request);
 
         // Headers.
-        response.headers(HeaderUtils.asStringHeaders(request.getHeaders()));
+        response.headers(HeaderUtils.asStringHeaders(request.getHeaders(), request.getConfiguration()));
 
         // Entity.
         if (request.hasEntity()) {
diff --git a/test-framework/util/src/main/java/org/glassfish/jersey/test/util/server/ContainerRequestBuilder.java b/test-framework/util/src/main/java/org/glassfish/jersey/test/util/server/ContainerRequestBuilder.java
index e997556..0ad87e9 100644
--- a/test-framework/util/src/main/java/org/glassfish/jersey/test/util/server/ContainerRequestBuilder.java
+++ b/test-framework/util/src/main/java/org/glassfish/jersey/test/util/server/ContainerRequestBuilder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019 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,11 +20,11 @@
 import java.net.URI;
 import java.util.Arrays;
 
+import javax.ws.rs.core.Configuration;
 import javax.ws.rs.core.Cookie;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.SecurityContext;
-import javax.ws.rs.ext.RuntimeDelegate;
 
 import org.glassfish.jersey.internal.MapPropertiesDelegate;
 import org.glassfish.jersey.internal.PropertiesDelegate;
@@ -46,25 +46,32 @@
      * Create new Jersey container request context builder. The builder and built request context are supposed to be used only
      * for testing purposes.
      *
-     * @param requestUri request URI.
-     * @param method     request HTTP method name.
+     * @param requestUri    request URI.
+     * @param method        request HTTP method name.
+     * @param configuration container request configuration
      * @return new builder instance.
      */
-    public static ContainerRequestBuilder from(final String requestUri, final String method) {
-        return from(null, requestUri, method);
+    public static ContainerRequestBuilder from(final String requestUri,
+                                               final String method,
+                                               final Configuration configuration) {
+        return from(null, requestUri, method, configuration);
     }
 
     /**
      * Create new Jersey container request context builder. The builder and built request context are supposed to be used only
      * for testing purposes.
      *
-     * @param baseUri    base application URI.
-     * @param requestUri request URI.
-     * @param method     request HTTP method name.
+     * @param baseUri       base application URI.
+     * @param requestUri    request URI.
+     * @param method        request HTTP method name.
+     * @param configuration container request configuration
      * @return new builder instance.
      */
-    public static ContainerRequestBuilder from(final String baseUri, final String requestUri, final String method) {
-        return from(baseUri, requestUri, method, null, null);
+    public static ContainerRequestBuilder from(final String baseUri,
+                                               final String requestUri,
+                                               final String method,
+                                               final Configuration configuration) {
+        return from(baseUri, requestUri, method, null, null, configuration);
     }
 
     /**
@@ -79,39 +86,48 @@
      *                           has not been authenticated by the container.
      * @param propertiesDelegate custom {@link PropertiesDelegate properties delegate} to be used by the context, may be
      *                           {@code null}.
+     * @param configuration      container request configuration
      * @return new builder instance.
      */
     public static ContainerRequestBuilder from(final String baseUri,
                                                final String requestUri,
                                                final String method,
                                                final SecurityContext securityContext,
-                                               final PropertiesDelegate propertiesDelegate) {
-        return new ContainerRequestBuilder(baseUri, requestUri, method, securityContext, propertiesDelegate);
+                                               final PropertiesDelegate propertiesDelegate,
+                                               final Configuration configuration) {
+        return new ContainerRequestBuilder(baseUri, requestUri, method, securityContext, propertiesDelegate, configuration);
     }
 
     /**
      * Create new Jersey container request context builder. The builder and built request context are supposed to be used only
      * for testing purposes.
      *
-     * @param requestUri request URI.
-     * @param method     request HTTP method name.
+     * @param requestUri    request URI.
+     * @param method        request HTTP method name.
+     * @param configuration container request configuration
      * @return new builder instance.
      */
-    public static ContainerRequestBuilder from(final URI requestUri, final String method) {
-        return from(null, requestUri, method);
+    public static ContainerRequestBuilder from(final URI requestUri,
+                                               final String method,
+                                               final Configuration configuration) {
+        return from(null, requestUri, method, configuration);
     }
 
     /**
      * Create new Jersey container request context builder. The builder and built request context are supposed to be used only
      * for testing purposes.
      *
-     * @param baseUri    base application URI.
-     * @param requestUri request URI.
-     * @param method     request HTTP method name.
+     * @param baseUri       base application URI.
+     * @param requestUri    request URI.
+     * @param method        request HTTP method name.
+     * @param configuration container request configuration
      * @return new builder instance.
      */
-    public static ContainerRequestBuilder from(final URI baseUri, final URI requestUri, final String method) {
-        return from(baseUri, requestUri, method, null, null);
+    public static ContainerRequestBuilder from(final URI baseUri,
+                                               final URI requestUri,
+                                               final String method,
+                                               final Configuration configuration) {
+        return from(baseUri, requestUri, method, null, null, configuration);
     }
 
     /**
@@ -126,14 +142,16 @@
      *                           has not been authenticated by the container.
      * @param propertiesDelegate custom {@link PropertiesDelegate properties delegate} to be used by the context, may be
      *                           {@code null}.
+     * @param configuration      container request configuration
      * @return new builder instance.
      */
     public static ContainerRequestBuilder from(final URI baseUri,
                                                final URI requestUri,
                                                final String method,
                                                final SecurityContext securityContext,
-                                               final PropertiesDelegate propertiesDelegate) {
-        return new ContainerRequestBuilder(baseUri, requestUri, method, securityContext, propertiesDelegate);
+                                               final PropertiesDelegate propertiesDelegate,
+                                               final Configuration configuration) {
+        return new ContainerRequestBuilder(baseUri, requestUri, method, securityContext, propertiesDelegate, configuration);
     }
 
     /**
@@ -147,12 +165,11 @@
         return (uri.isAbsolute() || strUri.charAt(0) == '/') ? uri : URI.create('/' + strUri);
     }
 
-    private final RuntimeDelegate delegate = RuntimeDelegate.getInstance();
     private final TestContainerRequest request;
+    private final Configuration configuration;
 
     /**
      * Create new Jersey container request context builder.
-     *
      * @param baseUri            base application URI.
      * @param requestUri         request URI.
      * @param method             request HTTP method name.
@@ -161,17 +178,20 @@
      *                           has not been authenticated by the container.
      * @param propertiesDelegate custom {@link PropertiesDelegate properties delegate} to be used by the context, may be
      *                           {@code null}.
+     * @param configuration      container request configuration
      */
     private ContainerRequestBuilder(final String baseUri,
                                     final String requestUri,
                                     final String method,
                                     final SecurityContext securityContext,
-                                    final PropertiesDelegate propertiesDelegate) {
+                                    final PropertiesDelegate propertiesDelegate,
+                                    final Configuration configuration) {
         this(baseUri == null || baseUri.isEmpty() ? null : URI.create(baseUri),
                 URI.create(requestUri),
                 method,
                 securityContext,
-                propertiesDelegate);
+                propertiesDelegate,
+                configuration);
     }
 
     /**
@@ -185,17 +205,21 @@
      *                           has not been authenticated by the container.
      * @param propertiesDelegate custom {@link PropertiesDelegate properties delegate} to be used by the context, may be
      *                           {@code null}.
+     * @param configuration      container request configuration
      */
     private ContainerRequestBuilder(final URI baseUri,
                                     final URI requestUri,
                                     final String method,
                                     final SecurityContext securityContext,
-                                    final PropertiesDelegate propertiesDelegate) {
+                                    final PropertiesDelegate propertiesDelegate,
+                                    final Configuration configuration) {
+        this.configuration = configuration;
         request = new TestContainerRequest(baseUri,
                 slash(requestUri),
                 method,
                 securityContext,
-                propertiesDelegate == null ? new MapPropertiesDelegate() : propertiesDelegate);
+                propertiesDelegate == null ? new MapPropertiesDelegate() : propertiesDelegate,
+                configuration);
     }
 
     /**
@@ -305,7 +329,7 @@
      * @return the updated builder.
      */
     public ContainerRequestBuilder type(final MediaType contentType) {
-        request.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE, HeaderUtils.asString(contentType, delegate));
+        request.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE, HeaderUtils.asString(contentType, configuration));
         return this;
     }
 
@@ -353,7 +377,7 @@
             request.getHeaders().remove(name);
             return;
         }
-        request.header(name, HeaderUtils.asString(value, delegate));
+        request.header(name, HeaderUtils.asString(value, configuration));
     }
 
     private void putHeaders(final String name, final Object... values) {
@@ -361,7 +385,7 @@
             request.getHeaders().remove(name);
             return;
         }
-        request.getHeaders().addAll(name, HeaderUtils.asStringList(Arrays.asList(values), delegate));
+        request.getHeaders().addAll(name, HeaderUtils.asStringList(Arrays.asList(values), configuration));
     }
 
     private void putHeaders(final String name, final String... values) {
diff --git a/test-framework/util/src/main/java/org/glassfish/jersey/test/util/server/TestContainerRequest.java b/test-framework/util/src/main/java/org/glassfish/jersey/test/util/server/TestContainerRequest.java
index 2c9bbec..d01ad35 100644
--- a/test-framework/util/src/main/java/org/glassfish/jersey/test/util/server/TestContainerRequest.java
+++ b/test-framework/util/src/main/java/org/glassfish/jersey/test/util/server/TestContainerRequest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019 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,6 +28,7 @@
 import java.util.logging.Logger;
 
 import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Configuration;
 import javax.ws.rs.core.GenericEntity;
 import javax.ws.rs.core.GenericType;
 import javax.ws.rs.core.MultivaluedHashMap;
@@ -52,8 +53,9 @@
                          final URI requestUri,
                          final String method,
                          final SecurityContext securityContext,
-                         final PropertiesDelegate propertiesDelegate) {
-        super(baseUri, requestUri, method, securityContext, propertiesDelegate);
+                         final PropertiesDelegate propertiesDelegate,
+                         final Configuration configuration) {
+        super(baseUri, requestUri, method, securityContext, propertiesDelegate, configuration);
     }
 
     void setEntity(final InputStream stream) {
diff --git a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/CommittingOutputStreamTest.java b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/CommittingOutputStreamTest.java
index 5361275..23f88b7 100644
--- a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/CommittingOutputStreamTest.java
+++ b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/CommittingOutputStreamTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -23,6 +23,7 @@
 import java.util.Map;
 
 import javax.ws.rs.RuntimeType;
+import javax.ws.rs.core.Configuration;
 
 import org.glassfish.jersey.CommonProperties;
 import org.glassfish.jersey.internal.util.PropertiesHelper;
@@ -273,7 +274,7 @@
     }
 
     private void checkBufferSize(int expectedSize, Map<String, Object> properties, RuntimeType runtime) throws IOException {
-        OutboundMessageContext outboundMessageContext = new OutboundMessageContext();
+        OutboundMessageContext outboundMessageContext = new OutboundMessageContext((Configuration) null);
         final Passed passed = new Passed();
         outboundMessageContext.setStreamProvider(new OutboundMessageContext.StreamProvider() {
             @Override
diff --git a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/HeaderUtilsTest.java b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/HeaderUtilsTest.java
index b64b311..7932181 100644
--- a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/HeaderUtilsTest.java
+++ b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/HeaderUtilsTest.java
@@ -135,7 +135,7 @@
 
     @Test
     public void testAsStringHeaders() throws Exception {
-        assertNull(HeaderUtils.asStringHeaders(null));
+        assertNull(HeaderUtils.asStringHeaders(null, null));
 
         final AbstractMultivaluedMap<String, Object> headers = HeaderUtils.createOutbound();
 
@@ -147,7 +147,7 @@
 
         headers.putSingle("k3", "value3");
 
-        final MultivaluedMap<String, String> stringHeaders = HeaderUtils.asStringHeaders(headers);
+        final MultivaluedMap<String, String> stringHeaders = HeaderUtils.asStringHeaders(headers, null);
 
         // test string values
         assertEquals(Arrays.asList("value", "value2"),
diff --git a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/InboundMessageContextTest.java b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/InboundMessageContextTest.java
index f61b225..bd29bb4 100644
--- a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/InboundMessageContextTest.java
+++ b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/InboundMessageContextTest.java
@@ -53,7 +53,7 @@
     }
 
     private static InboundMessageContext createInboundMessageContext() {
-        return new InboundMessageContext() {
+        return new InboundMessageContext(null) {
             @Override
             protected Iterable<ReaderInterceptor> getReaderInterceptors() {
                 return Collections.emptyList();
diff --git a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/OutboundJaxrsResponseBuilderTest.java b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/OutboundJaxrsResponseBuilderTest.java
index fb68693..f0257cd 100644
--- a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/OutboundJaxrsResponseBuilderTest.java
+++ b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/OutboundJaxrsResponseBuilderTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019 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,7 @@
 
 package org.glassfish.jersey.tests.e2e.common.message.internal;
 
+import javax.ws.rs.core.Configuration;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
@@ -47,7 +48,7 @@
      */
     @Test
     public void testMediaType() {
-        final Response r = new OutboundJaxrsResponse.Builder(new OutboundMessageContext())
+        final Response r = new OutboundJaxrsResponse.Builder(new OutboundMessageContext((Configuration) null))
                 .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_HTML)
                 .build();
         assertEquals(204, r.getStatus());
@@ -57,7 +58,7 @@
 
     @Test
     public void testIssue1297Fix() {
-        final Response response = new OutboundJaxrsResponse.Builder(new OutboundMessageContext())
+        final Response response = new OutboundJaxrsResponse.Builder(new OutboundMessageContext((Configuration) null))
                 .status(Response.Status.OK)
                 .entity("1234567890")
                 .build();
diff --git a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/OutboundJaxrsResponseTest.java b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/OutboundJaxrsResponseTest.java
index 47086bd..3267ad2 100644
--- a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/OutboundJaxrsResponseTest.java
+++ b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/OutboundJaxrsResponseTest.java
@@ -21,6 +21,7 @@
 import java.io.IOException;
 import java.io.OutputStream;
 
+import javax.ws.rs.core.Configuration;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.RuntimeDelegate;
 
@@ -97,7 +98,7 @@
 
     @Before
     public void setUp() {
-        rb = new OutboundJaxrsResponse.Builder(new OutboundMessageContext()).status(Response.Status.OK);
+        rb = new OutboundJaxrsResponse.Builder(new OutboundMessageContext((Configuration) null)).status(Response.Status.OK);
     }
 
 
@@ -106,7 +107,7 @@
      */
     @Test
     public void testBufferEmptyEntity() {
-        final OutboundJaxrsResponse r = OutboundJaxrsResponse.from(rb.build());
+        final OutboundJaxrsResponse r = OutboundJaxrsResponse.from(rb.build(), null);
         r.getContext().setStreamProvider(TEST_PROVIDER);
 
         assertFalse("Buffer entity should return 'false' if no entity.", r.bufferEntity());
@@ -117,7 +118,7 @@
      */
     @Test
     public void testBufferNonStreamEntity() {
-        final OutboundJaxrsResponse r = OutboundJaxrsResponse.from(rb.entity(new Object()).build());
+        final OutboundJaxrsResponse r = OutboundJaxrsResponse.from(rb.entity(new Object()).build(), null);
         r.getContext().setStreamProvider(TEST_PROVIDER);
 
         assertFalse("Buffer entity should return 'false' for non-stream entity.", r.bufferEntity());
@@ -129,7 +130,7 @@
     @Test
     public void testBufferStreamEntity() {
         TestInputStream tis = new TestInputStream();
-        final OutboundJaxrsResponse r = OutboundJaxrsResponse.from(rb.entity(tis).build());
+        final OutboundJaxrsResponse r = OutboundJaxrsResponse.from(rb.entity(tis).build(), null);
         r.getContext().setStreamProvider(TEST_PROVIDER);
 
         assertTrue("Buffer entity should return 'true' for stream entity.", r.bufferEntity());
@@ -143,7 +144,7 @@
      */
     @Test
     public void testCloseEmptyEntity() {
-        final OutboundJaxrsResponse r = OutboundJaxrsResponse.from(rb.build());
+        final OutboundJaxrsResponse r = OutboundJaxrsResponse.from(rb.build(), null);
         r.getContext().setStreamProvider(TEST_PROVIDER);
 
         r.close();
@@ -161,7 +162,7 @@
      */
     @Test
     public void testCloseNonStreamEntity() {
-        final OutboundJaxrsResponse r = OutboundJaxrsResponse.from(rb.entity(new Object()).build());
+        final OutboundJaxrsResponse r = OutboundJaxrsResponse.from(rb.entity(new Object()).build(), null);
         r.getContext().setStreamProvider(TEST_PROVIDER);
 
         r.close();
@@ -180,7 +181,7 @@
     @Test
     public void testCloseStreamEntity() {
         TestInputStream tis = new TestInputStream();
-        final OutboundJaxrsResponse r = OutboundJaxrsResponse.from(rb.entity(tis).build());
+        final OutboundJaxrsResponse r = OutboundJaxrsResponse.from(rb.entity(tis).build(), null);
         r.getContext().setStreamProvider(TEST_PROVIDER);
 
         r.close();
@@ -201,7 +202,7 @@
      */
     @Test
     public void testCloseEmptyEntityNoStreamProvider() {
-        final OutboundJaxrsResponse r = OutboundJaxrsResponse.from(rb.build());
+        final OutboundJaxrsResponse r = OutboundJaxrsResponse.from(rb.build(), null);
         r.close();
         try {
             r.bufferEntity();
@@ -217,7 +218,7 @@
      */
     @Test
     public void testCloseNonStreamEntityNoStreamProvider() {
-        final OutboundJaxrsResponse r = OutboundJaxrsResponse.from(rb.entity(new Object()).build());
+        final OutboundJaxrsResponse r = OutboundJaxrsResponse.from(rb.entity(new Object()).build(), null);
         r.close();
         try {
             r.bufferEntity();
@@ -234,7 +235,7 @@
     @Test
     public void testCloseStreamEntityNoStreamProvider() {
         TestInputStream tis = new TestInputStream();
-        final OutboundJaxrsResponse r = OutboundJaxrsResponse.from(rb.entity(tis).build());
+        final OutboundJaxrsResponse r = OutboundJaxrsResponse.from(rb.entity(tis).build(), null);
         r.close();
         try {
             r.bufferEntity();
diff --git a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/OutboundMessageContextTest.java b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/OutboundMessageContextTest.java
index c4cd221..2877594 100644
--- a/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/OutboundMessageContextTest.java
+++ b/tests/e2e-core-common/src/test/java/org/glassfish/jersey/tests/e2e/common/message/internal/OutboundMessageContextTest.java
@@ -25,6 +25,7 @@
 import java.util.Locale;
 
 import javax.ws.rs.ProcessingException;
+import javax.ws.rs.core.Configuration;
 import javax.ws.rs.core.EntityTag;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Link;
@@ -58,7 +59,7 @@
 
     @Test
     public void testAcceptableMediaTypes() throws URISyntaxException {
-        OutboundMessageContext r = new OutboundMessageContext();
+        OutboundMessageContext r = new OutboundMessageContext((Configuration) null);
 
         r.getHeaders().add(HttpHeaders.ACCEPT, "application/xml, text/plain");
         r.getHeaders().add(HttpHeaders.ACCEPT, "application/json");
@@ -72,7 +73,7 @@
 
     @Test
     public void testAcceptableLanguages() throws URISyntaxException {
-        OutboundMessageContext r = new OutboundMessageContext();
+        OutboundMessageContext r = new OutboundMessageContext((Configuration) null);
         r.getHeaders().add(HttpHeaders.ACCEPT_LANGUAGE, "en-gb;q=0.8, en;q=0.7");
         r.getHeaders().add(HttpHeaders.ACCEPT_LANGUAGE, "de");
         assertEquals(r.getAcceptableLanguages().size(), 3);
@@ -83,7 +84,7 @@
 
     @Test
     public void testRequestCookies() throws URISyntaxException {
-        OutboundMessageContext r = new OutboundMessageContext();
+        OutboundMessageContext r = new OutboundMessageContext((Configuration) null);
         r.getHeaders().add(HttpHeaders.COOKIE, "oreo=chocolate");
         r.getHeaders().add(HttpHeaders.COOKIE, "nilla=vanilla");
         assertEquals(r.getRequestCookies().size(), 2);
@@ -96,7 +97,7 @@
 
     @Test
     public void testDate() throws URISyntaxException, ParseException {
-        OutboundMessageContext r = new OutboundMessageContext();
+        OutboundMessageContext r = new OutboundMessageContext((Configuration) null);
         r.getHeaders().add(HttpHeaders.DATE, "Tue, 29 Jan 2002 22:14:02 -0500");
         SimpleDateFormat f = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss Z", Locale.ENGLISH);
         Date date = f.parse("Tue, 29 Jan 2002 22:14:02 -0500");
@@ -105,7 +106,7 @@
 
     @Test
     public void testHeader() throws URISyntaxException, ParseException {
-        OutboundMessageContext r = new OutboundMessageContext();
+        OutboundMessageContext r = new OutboundMessageContext((Configuration) null);
         r.getHeaders().add(HttpHeaders.ACCEPT, "application/xml, text/plain");
         r.getHeaders().add(HttpHeaders.ACCEPT, "application/json");
         r.getHeaders().add("FOO", "");
@@ -118,7 +119,7 @@
 
     @Test
     public void testHeaderMap() throws URISyntaxException, ParseException {
-        OutboundMessageContext r = new OutboundMessageContext();
+        OutboundMessageContext r = new OutboundMessageContext((Configuration) null);
         r.getHeaders().add(HttpHeaders.ACCEPT, "application/xml, text/plain");
         r.getHeaders().add(HttpHeaders.ACCEPT, "application/json");
         r.getHeaders().add("Allow", "GET, PUT");
@@ -131,7 +132,7 @@
 
     @Test
     public void testAllowedMethods() throws URISyntaxException {
-        OutboundMessageContext r = new OutboundMessageContext();
+        OutboundMessageContext r = new OutboundMessageContext((Configuration) null);
         r.getHeaders().add("Allow", "GET, PUT");
         r.getHeaders().add("Allow", "POST");
         assertEquals(3, r.getAllowedMethods().size());
@@ -143,7 +144,7 @@
 
     @Test
     public void testResponseCookies() throws URISyntaxException {
-        OutboundMessageContext r = new OutboundMessageContext();
+        OutboundMessageContext r = new OutboundMessageContext((Configuration) null);
         r.getHeaders().add(HttpHeaders.SET_COOKIE, "oreo=chocolate");
         r.getHeaders().add(HttpHeaders.SET_COOKIE, "nilla=vanilla");
         assertEquals(2, r.getResponseCookies().size());
@@ -153,14 +154,14 @@
 
     @Test
     public void testEntityTag() throws URISyntaxException {
-        OutboundMessageContext r = new OutboundMessageContext();
+        OutboundMessageContext r = new OutboundMessageContext((Configuration) null);
         r.getHeaders().add(HttpHeaders.ETAG, "\"tag\"");
         assertEquals(EntityTag.valueOf("\"tag\""), r.getEntityTag());
     }
 
     @Test
     public void testLastModified() throws URISyntaxException, ParseException {
-        OutboundMessageContext r = new OutboundMessageContext();
+        OutboundMessageContext r = new OutboundMessageContext((Configuration) null);
         r.getHeaders().add(HttpHeaders.LAST_MODIFIED, "Tue, 29 Jan 2002 22:14:02 -0500");
         SimpleDateFormat f = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss Z", Locale.ENGLISH);
         Date date = f.parse("Tue, 29 Jan 2002 22:14:02 -0500");
@@ -169,14 +170,14 @@
 
     @Test
     public void testLocation() throws URISyntaxException {
-        OutboundMessageContext r = new OutboundMessageContext();
+        OutboundMessageContext r = new OutboundMessageContext((Configuration) null);
         r.getHeaders().add(HttpHeaders.LOCATION, "http://example.org/app");
         assertEquals(URI.create("http://example.org/app"), r.getLocation());
     }
 
     @Test
     public void testGetLinks() {
-        OutboundMessageContext r = new OutboundMessageContext();
+        OutboundMessageContext r = new OutboundMessageContext((Configuration) null);
         Link link1 = Link.fromUri("http://example.org/app/link1").param("produces", "application/json").param("method", "GET").rel("self").build();
         Link link2 = Link.fromUri("http://example.org/app/link2").param("produces", "application/xml").param("method", "PUT").rel("self").build();
         r.getHeaders().add("Link", link1.toString());
@@ -188,7 +189,7 @@
 
     @Test
     public void testGetLink() {
-        OutboundMessageContext r = new OutboundMessageContext();
+        OutboundMessageContext r = new OutboundMessageContext((Configuration) null);
         Link link1 = Link.fromUri("http://example.org/app/link1").param("produces", "application/json").param("method", "GET").rel("self").build();
         Link link2 = Link.fromUri("http://example.org/app/link2").param("produces", "application/xml").param("method", "PUT").rel("update").build();
         Link link3 = Link.fromUri("http://example.org/app/link2").param("produces", "application/xml").param("method", "POST").rel("update").build();
@@ -201,14 +202,14 @@
 
     @Test
     public void testGetLength() {
-        OutboundMessageContext r = new OutboundMessageContext();
+        OutboundMessageContext r = new OutboundMessageContext((Configuration) null);
         r.getHeaders().add("Content-Length", 50);
         assertEquals(50, r.getLengthLong());
     }
 
     @Test
     public void testGetLength_tooLongForInt() {
-        OutboundMessageContext r = new OutboundMessageContext();
+        OutboundMessageContext r = new OutboundMessageContext((Configuration) null);
         long length = Integer.MAX_VALUE + 5L;
         r.getHeaders().add("Content-Length", length);
 
diff --git a/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/header/HeaderDelegateProviderTest.java b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/header/HeaderDelegateProviderTest.java
new file mode 100644
index 0000000..a6acb9a
--- /dev/null
+++ b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/header/HeaderDelegateProviderTest.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2019 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.header;
+
+import org.glassfish.jersey.CommonProperties;
+import org.glassfish.jersey.internal.ServiceFinder;
+import org.glassfish.jersey.message.internal.HeaderUtils;
+import org.glassfish.jersey.spi.HeaderDelegateProvider;
+import org.junit.Assert;
+import org.junit.Test;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientRequestFilter;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerResponseContext;
+import javax.ws.rs.container.ContainerResponseFilter;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+public class HeaderDelegateProviderTest {
+    static final String HEADER_NAME = "BEAN_HEADER";
+    static final String DISABLED_VALUE = new BeanForHeaderDelegateProviderTest().toString();
+
+    public static class BeanHeaderDelegateProvider implements HeaderDelegateProvider<BeanForHeaderDelegateProviderTest> {
+
+        @Override
+        public boolean supports(Class type) {
+            return BeanForHeaderDelegateProviderTest.class == type;
+        }
+
+        @Override
+        public BeanForHeaderDelegateProviderTest fromString(String value) {
+            return new BeanForHeaderDelegateProviderTest();
+        }
+
+        @Override
+        public String toString(BeanForHeaderDelegateProviderTest value) {
+            return value.getValue();
+        }
+    }
+
+    public static class BeanForHeaderDelegateProviderTest {
+        public static String getValue() {
+            return "CORRECT_VALUE";
+        }
+
+        @Override
+        public String toString() {
+            return "INVALID_VALUE";
+        }
+    }
+
+    @Path("/")
+    public static final class HeaderSettingResource {
+        @GET
+        @Path("/simple")
+        public Response simple() {
+            return Response.ok().header(HEADER_NAME, new BeanForHeaderDelegateProviderTest()).build();
+        }
+
+        @GET
+        @Path("/headers")
+        public Response headers(@Context HttpHeaders headers) {
+            return Response.ok()
+                    .header(HeaderSettingResource.class.getSimpleName(), headers.getHeaderString(HEADER_NAME)).build();
+        }
+
+        @GET
+        @Path("/clientfilter")
+        public Response clientFilterTest(@Context HttpHeaders headers) {
+            return Response.ok(headers.getHeaderString(HeaderClientRequestFilter.class.getSimpleName())).build();
+        }
+    }
+
+    public static final class HeaderContainerResponseFilter implements ContainerResponseFilter {
+        @Override
+        public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
+            String value = responseContext.getHeaderString(HEADER_NAME);
+            responseContext.getHeaders().putSingle(HeaderContainerResponseFilter.class.getSimpleName(), value);
+        }
+    }
+
+    public static final class HeaderClientRequestFilter implements ClientRequestFilter {
+        @Override
+        public void filter(ClientRequestContext requestContext) throws IOException {
+            requestContext.getHeaders().putSingle(
+                    HeaderClientRequestFilter.class.getSimpleName(), new BeanForHeaderDelegateProviderTest()
+            );
+        }
+    }
+
+    @Test
+    public void testTheProviderIsFound() {
+        for (HeaderDelegateProvider provider : ServiceFinder.find(HeaderDelegateProvider.class, true)) {
+            Assert.assertEquals(provider.getClass(), BeanHeaderDelegateProvider.class);
+        }
+    }
+
+    @Test
+    public void headerDelegateIsUsedWhenRuntimeDelegateDecoratorIsUsed() {
+        MultivaluedHashMap headers = new MultivaluedHashMap();
+        headers.put(HEADER_NAME, Arrays.asList(new BeanForHeaderDelegateProviderTest()));
+        MultivaluedMap<String, String> converted = HeaderUtils.asStringHeaders(headers, null);
+        testMap(converted, BeanForHeaderDelegateProviderTest.getValue());
+
+        Client client = ClientBuilder.newClient().property(CommonProperties.METAINF_SERVICES_LOOKUP_DISABLE, false);
+        converted = HeaderUtils.asStringHeaders(headers, client.getConfiguration());
+        testMap(converted, BeanForHeaderDelegateProviderTest.getValue());
+    }
+
+    @Test
+    public void headerDelegateIsNotUsed() {
+        MultivaluedHashMap headers = new MultivaluedHashMap();
+        headers.put(HEADER_NAME, Arrays.asList(new BeanForHeaderDelegateProviderTest()));
+
+        Client client = ClientBuilder.newClient().property(CommonProperties.METAINF_SERVICES_LOOKUP_DISABLE, true);
+        MultivaluedMap<String, String> converted = HeaderUtils.asStringHeaders(headers, client.getConfiguration());
+        testMap(converted, DISABLED_VALUE);
+
+        client = ClientBuilder.newClient().property(CommonProperties.METAINF_SERVICES_LOOKUP_DISABLE_CLIENT, true);
+        converted = HeaderUtils.asStringHeaders(headers, client.getConfiguration());
+        testMap(converted, DISABLED_VALUE);
+    }
+
+    private void testMap(MultivaluedMap<String, String> map, String expectedValue) {
+        for (Map.Entry<String, List<String>> entry : map.entrySet()) {
+            Assert.assertEquals(HEADER_NAME, entry.getKey());
+            Assert.assertEquals(expectedValue, entry.getValue().iterator().next());
+        }
+    }
+}
diff --git a/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/header/RuntimeDelegateProviderDisabledTest.java b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/header/RuntimeDelegateProviderDisabledTest.java
new file mode 100644
index 0000000..d2a03d7
--- /dev/null
+++ b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/header/RuntimeDelegateProviderDisabledTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2019 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.header;
+
+import org.glassfish.jersey.CommonProperties;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.Response;
+
+import static org.glassfish.jersey.tests.e2e.header.HeaderDelegateProviderTest.DISABLED_VALUE;
+import static org.glassfish.jersey.tests.e2e.header.HeaderDelegateProviderTest.HEADER_NAME;
+
+public class RuntimeDelegateProviderDisabledTest extends JerseyTest {
+    @Override
+    protected Application configure() {
+        return new ResourceConfig(HeaderDelegateProviderTest.HeaderSettingResource.class,
+                HeaderDelegateProviderTest.HeaderContainerResponseFilter.class)
+                .property(CommonProperties.METAINF_SERVICES_LOOKUP_DISABLE_SERVER, true);
+    }
+
+    @Test
+    public void testClientResponseHeaders() {
+        try (Response response = target("/simple").request().get()) {
+            Assert.assertEquals(
+                    DISABLED_VALUE,
+                    response.getHeaderString(HeaderDelegateProviderTest.HeaderContainerResponseFilter.class.getSimpleName())
+            );
+            Assert.assertEquals(
+                    DISABLED_VALUE,
+                    response.getStringHeaders().getFirst(HEADER_NAME)
+            );
+        }
+    }
+
+    @Test
+    public void testContainerResponseFilter() {
+        try (Response response = target("/simple").request().get()) {
+            Assert.assertEquals(DISABLED_VALUE, response.getHeaderString(HEADER_NAME));
+        }
+    }
+
+    @Test
+    public void testProviderOnClientDisabled() {
+        try (Response response = target("/headers")
+                .property(CommonProperties.METAINF_SERVICES_LOOKUP_DISABLE_CLIENT, true).request()
+                .header(HEADER_NAME, new HeaderDelegateProviderTest.BeanForHeaderDelegateProviderTest())
+                .get()) {
+            Assert.assertEquals(
+                    DISABLED_VALUE,
+                    response.getHeaderString(HeaderDelegateProviderTest.HeaderSettingResource.class.getSimpleName())
+            );
+        }
+    }
+
+    @Test
+    public void testProviderOnClientFilter() {
+        try (Response response = target("/clientfilter")
+                .property(CommonProperties.METAINF_SERVICES_LOOKUP_DISABLE_CLIENT, true)
+                .register(HeaderDelegateProviderTest.HeaderClientRequestFilter.class)
+                .request().get()) {
+            Assert.assertEquals(
+                    DISABLED_VALUE,
+                    response.readEntity(String.class)
+            );
+        }
+    }
+}
diff --git a/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/header/RuntimeDelegateProviderEnabledTest.java b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/header/RuntimeDelegateProviderEnabledTest.java
new file mode 100644
index 0000000..2f3c73d
--- /dev/null
+++ b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/header/RuntimeDelegateProviderEnabledTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2019 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.header;
+
+import org.glassfish.jersey.CommonProperties;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.Response;
+
+import static org.glassfish.jersey.tests.e2e.header.HeaderDelegateProviderTest.HEADER_NAME;
+
+public class RuntimeDelegateProviderEnabledTest extends JerseyTest {
+    @Override
+    protected Application configure() {
+        return new ResourceConfig(HeaderDelegateProviderTest.HeaderSettingResource.class,
+                HeaderDelegateProviderTest.HeaderContainerResponseFilter.class);
+    }
+
+    @Test
+    public void testClientResponseHeaders() {
+        try (Response response = target("/simple").request().get()) {
+            Assert.assertEquals(
+                    HeaderDelegateProviderTest.BeanForHeaderDelegateProviderTest.getValue(),
+                    response.getHeaderString(HeaderDelegateProviderTest.HeaderContainerResponseFilter.class.getSimpleName())
+            );
+            Assert.assertEquals(
+                    HeaderDelegateProviderTest.BeanForHeaderDelegateProviderTest.getValue(),
+                    response.getStringHeaders().getFirst(HEADER_NAME)
+            );
+        }
+    }
+
+    @Test
+    public void testContainerResponseFilter() {
+        try (Response response = target("/simple").request().get()) {
+            Assert.assertEquals(
+                    HeaderDelegateProviderTest.BeanForHeaderDelegateProviderTest.getValue(),
+                    response.getHeaderString(HEADER_NAME)
+            );
+        }
+    }
+
+    @Test
+    public void testProviderOnClient() {
+        try (Response response = target("/headers").request()
+                .header(HEADER_NAME, new HeaderDelegateProviderTest.BeanForHeaderDelegateProviderTest()).get()) {
+            Assert.assertEquals(
+                    HeaderDelegateProviderTest.BeanForHeaderDelegateProviderTest.getValue(),
+                    response.getHeaderString(HeaderDelegateProviderTest.HeaderSettingResource.class.getSimpleName())
+            );
+        }
+    }
+
+    @Test
+    public void testProviderOnClientFilter() {
+        try (Response response = target("/clientfilter")
+                .register(HeaderDelegateProviderTest.HeaderClientRequestFilter.class)
+                .request().get()) {
+            Assert.assertEquals(
+                    HeaderDelegateProviderTest.BeanForHeaderDelegateProviderTest.getValue(),
+                    response.readEntity(String.class)
+            );
+        }
+    }
+}
diff --git a/tests/e2e-entity/src/test/resources/META-INF/services/org.glassfish.jersey.spi.HeaderDelegateProvider b/tests/e2e-entity/src/test/resources/META-INF/services/org.glassfish.jersey.spi.HeaderDelegateProvider
new file mode 100644
index 0000000..1cca664
--- /dev/null
+++ b/tests/e2e-entity/src/test/resources/META-INF/services/org.glassfish.jersey.spi.HeaderDelegateProvider
@@ -0,0 +1 @@
+org.glassfish.jersey.tests.e2e.header.HeaderDelegateProviderTest$BeanHeaderDelegateProvider
\ No newline at end of file
diff --git a/tests/e2e-inject/cdi2-se/src/test/java/org/glassfish/jersey/tests/e2e/inject/cdi/se/RequestContextBuilder.java b/tests/e2e-inject/cdi2-se/src/test/java/org/glassfish/jersey/tests/e2e/inject/cdi/se/RequestContextBuilder.java
index 3b06a47..1b0698d 100644
--- a/tests/e2e-inject/cdi2-se/src/test/java/org/glassfish/jersey/tests/e2e/inject/cdi/se/RequestContextBuilder.java
+++ b/tests/e2e-inject/cdi2-se/src/test/java/org/glassfish/jersey/tests/e2e/inject/cdi/se/RequestContextBuilder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019 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
@@ -36,7 +36,6 @@
 import javax.ws.rs.core.MultivaluedHashMap;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.SecurityContext;
-import javax.ws.rs.ext.RuntimeDelegate;
 import javax.ws.rs.ext.WriterInterceptor;
 
 import org.glassfish.jersey.internal.MapPropertiesDelegate;
@@ -63,7 +62,7 @@
                                     final String method,
                                     final SecurityContext securityContext,
                                     final PropertiesDelegate propertiesDelegate) {
-            super(baseUri, requestUri, method, securityContext, propertiesDelegate);
+            super(baseUri, requestUri, method, securityContext, propertiesDelegate, null);
             this.propertiesDelegate = propertiesDelegate;
         }
 
@@ -109,7 +108,6 @@
         }
     }
 
-    private final RuntimeDelegate delegate = RuntimeDelegate.getInstance();
     private final TestContainerRequest request;
 
     public static RequestContextBuilder from(final String requestUri, final String method) {
@@ -163,7 +161,7 @@
     }
 
     public RequestContextBuilder type(final MediaType contentType) {
-        request.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE, HeaderUtils.asString(contentType, delegate));
+        request.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE, HeaderUtils.asString(contentType, request.getConfiguration()));
         return this;
     }
 
@@ -187,7 +185,7 @@
             request.getHeaders().remove(name);
             return;
         }
-        request.header(name, HeaderUtils.asString(value, delegate));
+        request.header(name, HeaderUtils.asString(value, request.getConfiguration()));
     }
 
     private void putHeaders(final String name, final Object... values) {
@@ -195,7 +193,7 @@
             request.getHeaders().remove(name);
             return;
         }
-        request.getHeaders().addAll(name, HeaderUtils.asStringList(Arrays.asList(values), delegate));
+        request.getHeaders().addAll(name, HeaderUtils.asStringList(Arrays.asList(values), request.getConfiguration()));
     }
 
     private void putHeaders(final String name, final String... values) {
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/validation/PropertyValidationTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/validation/PropertyValidationTest.java
index e9d7c09..92ce1a6 100644
--- a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/validation/PropertyValidationTest.java
+++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/validation/PropertyValidationTest.java
@@ -180,7 +180,8 @@
     private void assertApply(int responseStatus, ResourceConfig resourceConfig, URI uri)
             throws InterruptedException, ExecutionException {
         final ApplicationHandler applicationHandler = new ApplicationHandler(resourceConfig);
-        final ContainerRequest requestContext = new ContainerRequest(uri, uri, "POST", null, new MapPropertiesDelegate());
+        final ContainerRequest requestContext =
+                new ContainerRequest(uri, uri, "POST", null, new MapPropertiesDelegate(), resourceConfig);
         final ContainerResponse containerResponse = applicationHandler.apply(requestContext).get();
 
         assertEquals(responseStatus, containerResponse.getStatus());
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlResourceTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlResourceTest.java
index a2a739c..f8a7a5c 100644
--- a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlResourceTest.java
+++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/wadl/WadlResourceTest.java
@@ -280,7 +280,7 @@
 
             final ContainerResponse containerResponse = applicationHandler.apply(new ContainerRequest(
                     URI.create("/"), URI.create("/application.wadl"),
-                    "GET", null, new MapPropertiesDelegate())).get();
+                    "GET", null, new MapPropertiesDelegate(), rc)).get();
 
             assertEquals(404, containerResponse.getStatus());
         }
@@ -294,7 +294,7 @@
 
             final ContainerResponse containerResponse = applicationHandler.apply(new ContainerRequest(
                     URI.create("/"), URI.create("/application.wadl"),
-                    "GET", null, new MapPropertiesDelegate())).get();
+                    "GET", null, new MapPropertiesDelegate(), rc)).get();
 
             assertEquals(200, containerResponse.getStatus());
         }
@@ -590,7 +590,7 @@
 
             final ContainerResponse containerResponse = applicationHandler.apply(new ContainerRequest(
                     URI.create("/"), URI.create("/application.wadl"),
-                    "GET", null, new MapPropertiesDelegate())).get();
+                    "GET", null, new MapPropertiesDelegate(), rc)).get();
 
             final DocumentBuilderFactory bf = DocumentBuilderFactory.newInstance();
             bf.setNamespaceAware(true);
@@ -637,7 +637,7 @@
 
             final ContainerResponse containerResponse = applicationHandler.apply(new ContainerRequest(
                     URI.create("/"), URI.create("/application.wadl"),
-                    "GET", null, new MapPropertiesDelegate())).get();
+                    "GET", null, new MapPropertiesDelegate(), rc)).get();
 
             assertEquals(200, containerResponse.getStatus());
 
diff --git a/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/ResponseTest.java b/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/ResponseTest.java
index 2471f59..acac1b7 100644
--- a/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/ResponseTest.java
+++ b/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/ResponseTest.java
@@ -247,7 +247,7 @@
         }
 
         MultivaluedMap<String, String> mvp = HeaderUtils.asStringHeaders(
-                resp.getMetadata());
+                resp.getMetadata(), null);
 
         for (String key : mvp.keySet()) {
             sb.append(indent + "Processing Key found in response: ").append(key).append(": ").append(mvp.get(key)).append("; ")
diff --git a/tests/performance/benchmarks/src/main/java/org/glassfish/jersey/tests/performance/benchmark/JacksonBenchmark.java b/tests/performance/benchmarks/src/main/java/org/glassfish/jersey/tests/performance/benchmark/JacksonBenchmark.java
index 8b527ff..f0e61b7 100644
--- a/tests/performance/benchmarks/src/main/java/org/glassfish/jersey/tests/performance/benchmark/JacksonBenchmark.java
+++ b/tests/performance/benchmarks/src/main/java/org/glassfish/jersey/tests/performance/benchmark/JacksonBenchmark.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019 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,7 +71,7 @@
     @Setup(Level.Iteration)
     public void request() {
         request = ContainerRequestBuilder
-                .from(path, "GET")
+                .from(path, "GET", handler.getConfiguration())
                 .build();
     }
 
diff --git a/tests/performance/benchmarks/src/main/java/org/glassfish/jersey/tests/performance/benchmark/LocatorBenchmark.java b/tests/performance/benchmarks/src/main/java/org/glassfish/jersey/tests/performance/benchmark/LocatorBenchmark.java
index e4c9da9..eaedd3e 100644
--- a/tests/performance/benchmarks/src/main/java/org/glassfish/jersey/tests/performance/benchmark/LocatorBenchmark.java
+++ b/tests/performance/benchmarks/src/main/java/org/glassfish/jersey/tests/performance/benchmark/LocatorBenchmark.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019 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
@@ -72,7 +72,7 @@
     @Setup(Level.Iteration)
     public void request() {
         request = ContainerRequestBuilder
-                .from(path, method)
+                .from(path, method, handler.getConfiguration())
                 .entity("GET".equals(method) ? null : "Hello World!", handler)
                 .build();
     }