Merge pull request #5543 from jansupol/m242b

Merge 2.x into 3.0
diff --git a/NOTICE.md b/NOTICE.md
index a737757..472637c 100644
--- a/NOTICE.md
+++ b/NOTICE.md
@@ -70,7 +70,7 @@
 * Project: http://www.javassist.org/

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

 

-Jackson JAX-RS Providers Version 2.15.3

+Jackson JAX-RS Providers Version 2.16.1

 * License: Apache License, 2.0

 * Project: https://github.com/FasterXML/jackson-jaxrs-providers

 * Copyright: (c) 2009-2023 FasterXML, LLC. All rights reserved unless otherwise indicated.

diff --git a/connectors/jdk-connector/pom.xml b/connectors/jdk-connector/pom.xml
index 54a3c95..72b29d9 100644
--- a/connectors/jdk-connector/pom.xml
+++ b/connectors/jdk-connector/pom.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <!--
 
-    Copyright (c) 2011, 2023 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2011, 2024 Oracle and/or its affiliates. All rights reserved.
 
     This program and the accompanying materials are made available under the
     terms of the Eclipse Public License v. 2.0, which is available at
diff --git a/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/SslFilterTLS13UrlStoresTest.java b/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/SslFilterTLS13UrlStoresTest.java
new file mode 100644
index 0000000..b8e96c0
--- /dev/null
+++ b/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/SslFilterTLS13UrlStoresTest.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.jdk.connector.internal;
+
+import org.glassfish.jersey.SslConfigurator;
+
+public class SslFilterTLS13UrlStoresTest extends SslFilterTest {
+
+    public SslFilterTLS13UrlStoresTest() {
+        System.setProperty("jdk.tls.server.protocols", "TLSv1.3");
+        System.setProperty("jdk.tls.client.protocols", "TLSv1.3");
+    }
+
+    @Override
+    protected SslConfigurator getSslConfigurator() {
+        return SslConfigurator.newInstance()
+                .trustStoreUrl(this.getClass().getResource("/truststore_client"))
+                .trustStorePassword("asdfgh")
+                .keyStoreUrl(this.getClass().getResource("/keystore_client"))
+                .keyStorePassword("asdfgh");
+    }
+}
diff --git a/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/SslFilterTest.java b/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/SslFilterTest.java
index ef13997..7f3b00a 100644
--- a/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/SslFilterTest.java
+++ b/connectors/jdk-connector/src/test/java/org/glassfish/jersey/jdk/connector/internal/SslFilterTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -388,11 +388,7 @@
                                                                                     final CountDownLatch completionLatch,
                                                                                     HostnameVerifier customHostnameVerifier)
             throws Throwable {
-        SslConfigurator sslConfig = SslConfigurator.newInstance()
-                .trustStoreFile(this.getClass().getResource("/truststore_client").getPath())
-                .trustStorePassword("asdfgh")
-                .keyStoreFile(this.getClass().getResource("/keystore_client").getPath())
-                .keyStorePassword("asdfgh");
+        SslConfigurator sslConfig = getSslConfigurator();
 
         TransportFilter transportFilter = new TransportFilter(17_000, ThreadPoolConfig.defaultConfig(), 100_000);
         final SSLParamConfigurator sslParamConfigurator = SSLParamConfigurator.builder()
@@ -481,6 +477,14 @@
         return clientSocket;
     }
 
+    protected SslConfigurator getSslConfigurator() {
+        return SslConfigurator.newInstance()
+                .trustStoreFile(this.getClass().getResource("/truststore_client").getPath())
+                .trustStorePassword("asdfgh")
+                .keyStoreFile(this.getClass().getResource("/keystore_client").getPath())
+                .keyStorePassword("asdfgh");
+    }
+
     /**
      * SSL echo server. It expects a message to be terminated with \n.
      */
diff --git a/core-common/src/main/java/org/glassfish/jersey/SslConfigurator.java b/core-common/src/main/java/org/glassfish/jersey/SslConfigurator.java
index b3befea..2bef140 100644
--- a/core-common/src/main/java/org/glassfish/jersey/SslConfigurator.java
+++ b/core-common/src/main/java/org/glassfish/jersey/SslConfigurator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -21,6 +21,7 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.URL;
 import java.nio.file.Files;
 import java.security.AccessController;
 import java.security.KeyManagementException;
@@ -31,6 +32,7 @@
 import java.security.UnrecoverableKeyException;
 import java.security.cert.CertificateException;
 import java.util.Arrays;
+import java.util.Objects;
 import java.util.Properties;
 import java.util.logging.Logger;
 
@@ -241,6 +243,9 @@
     private String trustStoreFile;
     private String keyStoreFile;
 
+    private URL trustStoreUrl;
+    private URL keyStoreUrl;
+
     private byte[] trustStoreBytes;
     private byte[] keyStoreBytes;
 
@@ -321,6 +326,8 @@
         this.keyPass = that.keyPass;
         this.trustStoreFile = that.trustStoreFile;
         this.keyStoreFile = that.keyStoreFile;
+        this.keyStoreUrl = that.keyStoreUrl;
+        this.trustStoreUrl = that.trustStoreUrl;
         this.trustStoreBytes = that.trustStoreBytes;
         this.keyStoreBytes = that.keyStoreBytes;
         this.trustManagerFactoryAlgorithm = that.trustManagerFactoryAlgorithm;
@@ -441,8 +448,9 @@
     /**
      * Set the <em>trust</em> store file name.
      * <p>
-     * Setting a trust store instance resets any {@link #trustStore(java.security.KeyStore) trust store instance}
-     * or {@link #trustStoreBytes(byte[]) trust store payload} value previously set.
+     * Setting a trust store instance resets any {@link #trustStore(java.security.KeyStore) trust store instance},
+     * {@link #trustStoreBytes(byte[]) trust store payload} or {@link #trustStoreUrl(URL) trust store url}
+     * value previously set.
      * </p>
      *
      * @param fileName {@link java.io.File file} name of the <em>trust</em> store.
@@ -451,6 +459,26 @@
     public SslConfigurator trustStoreFile(String fileName) {
         this.trustStoreFile = fileName;
         this.trustStoreBytes = null;
+        this.trustStoreUrl = null;
+        this.trustStore = null;
+        return this;
+    }
+
+    /**
+     * Set the <em>trust</em> store file url.
+     * <p>
+     * Setting a trust store instance resets any {@link #trustStore(java.security.KeyStore) trust store instance},
+     * {@link #trustStoreBytes(byte[]) trust store payload} or {@link #trustStoreUrl(URL) trust store url}
+     * value previously set.
+     * </p>
+     *
+     * @param url {@link java.net.URL url} link of the <em>trust</em> store.
+     * @return updated SSL configurator instance.
+     */
+    public SslConfigurator trustStoreUrl(URL url) {
+        this.trustStoreFile = null;
+        this.trustStoreBytes = null;
+        this.trustStoreUrl = url;
         this.trustStore = null;
         return this;
     }
@@ -458,8 +486,9 @@
     /**
      * Set the <em>trust</em> store payload as byte array.
      * <p>
-     * Setting a trust store instance resets any {@link #trustStoreFile(String) trust store file}
-     * or {@link #trustStore(java.security.KeyStore) trust store instance} value previously set.
+     * Setting a trust store instance resets any {@link #trustStoreFile(String) trust store file},
+     * {@link #trustStore(java.security.KeyStore) trust store instance} or {@link #trustStoreUrl(URL) trust store url}
+     * value previously set.
      * </p>
      *
      * @param payload <em>trust</em> store payload.
@@ -468,6 +497,7 @@
     public SslConfigurator trustStoreBytes(byte[] payload) {
         this.trustStoreBytes = payload.clone();
         this.trustStoreFile = null;
+        this.trustStoreUrl = null;
         this.trustStore = null;
         return this;
     }
@@ -475,8 +505,8 @@
     /**
      * Set the <em>key</em> store file name.
      * <p>
-     * Setting a key store instance resets any {@link #keyStore(java.security.KeyStore) key store instance}
-     * or {@link #keyStoreBytes(byte[]) key store payload} value previously set.
+     * Setting a key store instance resets any {@link #keyStore(java.security.KeyStore) key store instance},
+     * {@link #keyStoreBytes(byte[]) key store payload} or {@link #keyStoreUrl(URL) key store url} value previously set.
      * </p>
      *
      * @param fileName {@link java.io.File file} name of the <em>key</em> store.
@@ -484,6 +514,26 @@
      */
     public SslConfigurator keyStoreFile(String fileName) {
         this.keyStoreFile = fileName;
+        this.keyStoreUrl = null;
+        this.keyStoreBytes = null;
+        this.keyStore = null;
+        return this;
+    }
+
+    /**
+     * Set the <em>key</em> store url.
+     * <p>
+     * Setting a key store instance resets any {@link #keyStore(java.security.KeyStore) key store instance},
+     * {@link #keyStoreBytes(byte[]) key store payload} or {@link #keyStoreFile(String) key store file}
+     * value previously set.
+     * </p>
+     *
+     * @param url {@link java.net.URL url} of the <em>key</em> store.
+     * @return updated SSL configurator instance.
+     */
+    public SslConfigurator keyStoreUrl(URL url) {
+        this.keyStoreFile = null;
+        this.keyStoreUrl = url;
         this.keyStoreBytes = null;
         this.keyStore = null;
         return this;
@@ -492,8 +542,9 @@
     /**
      * Set the <em>key</em> store payload as byte array.
      * <p>
-     * Setting a key store instance resets any {@link #keyStoreFile(String) key store file}
-     * or {@link #keyStore(java.security.KeyStore) key store instance} value previously set.
+     * Setting a key store instance resets any {@link #keyStoreFile(String) key store file},
+     * {@link #keyStore(java.security.KeyStore) key store instance} or {@link #keyStoreUrl(URL) key store url}
+     * value previously set.
      * </p>
      *
      * @param payload <em>key</em> store payload.
@@ -501,6 +552,7 @@
      */
     public SslConfigurator keyStoreBytes(byte[] payload) {
         this.keyStoreBytes = payload.clone();
+        this.keyStoreUrl = null;
         this.keyStoreFile = null;
         this.keyStore = null;
         return this;
@@ -573,8 +625,8 @@
     /**
      * Set the <em>key</em> store instance.
      * <p>
-     * Setting a key store instance resets any {@link #keyStoreFile(String) key store file}
-     * or {@link #keyStoreBytes(byte[]) key store payload} value previously set.
+     * Setting a key store instance resets any {@link #keyStoreFile(String) key store file},
+     * {@link #keyStoreBytes(byte[]) key store payload} or {@link #keyStoreUrl(URL) key store url} value previously set.
      * </p>
      *
      * @param keyStore <em>key</em> store instance.
@@ -584,15 +636,12 @@
         this.keyStore = keyStore;
         this.keyStoreFile = null;
         this.keyStoreBytes = null;
+        this.keyStoreUrl = null;
         return this;
     }
 
     /**
      * Get the <em>trust</em> store instance.
-     * <p>
-     * Setting a trust store instance resets any {@link #trustStoreFile(String) trust store file}
-     * or {@link #trustStoreBytes(byte[]) trust store payload} value previously set.
-     * </p>
      *
      * @return <em>trust</em> store instance or {@code null} if not explicitly set.
      */
@@ -602,12 +651,16 @@
 
     /**
      * Set the <em>trust</em> store instance.
-     *
+     * <p>
+     * Setting a trust store instance resets any {@link #trustStoreFile(String) trust store file},
+     * {@link #trustStoreBytes(byte[]) trust store payload} or {@link #trustStoreUrl(URL) trust store url} value previously set.
+     * </p>
      * @param trustStore <em>trust</em> store instance.
      * @return updated SSL configurator instance.
      */
     public SslConfigurator trustStore(KeyStore trustStore) {
         this.trustStore = trustStore;
+        this.trustStoreUrl = null;
         this.trustStoreFile = null;
         this.trustStoreBytes = null;
         return this;
@@ -623,7 +676,7 @@
         KeyManagerFactory keyManagerFactory = null;
 
         KeyStore _keyStore = keyStore;
-        if (_keyStore == null && (keyStoreBytes != null || keyStoreFile != null)) {
+        if (_keyStore == null && (keyStoreBytes != null || keyStoreFile != null || keyStoreUrl != null)) {
             try {
                 if (keyStoreProvider != null) {
                     _keyStore = KeyStore.getInstance(
@@ -635,6 +688,8 @@
                 try {
                     if (keyStoreBytes != null) {
                         keyStoreInputStream = new ByteArrayInputStream(keyStoreBytes);
+                    } else if (keyStoreUrl != null) {
+                      keyStoreInputStream = keyStoreUrl.openStream();
                     } else if (!keyStoreFile.equals("NONE")) {
                         keyStoreInputStream = Files.newInputStream(new File(keyStoreFile).toPath());
                     }
@@ -697,7 +752,7 @@
         }
 
         KeyStore _trustStore = trustStore;
-        if (_trustStore == null && (trustStoreBytes != null || trustStoreFile != null)) {
+        if (_trustStore == null && (trustStoreBytes != null || trustStoreFile != null || trustStoreUrl != null)) {
             try {
                 if (trustStoreProvider != null) {
                     _trustStore = KeyStore.getInstance(
@@ -710,6 +765,8 @@
                 try {
                     if (trustStoreBytes != null) {
                         trustStoreInputStream = new ByteArrayInputStream(trustStoreBytes);
+                    } else if (trustStoreUrl != null) {
+                      trustStoreInputStream = trustStoreUrl.openStream();
                     } else if (!trustStoreFile.equals("NONE")) {
                         trustStoreInputStream = Files.newInputStream(new File(trustStoreFile).toPath());
                     }
@@ -808,6 +865,9 @@
         trustStoreFile = props.getProperty(TRUST_STORE_FILE);
         keyStoreFile = props.getProperty(KEY_STORE_FILE);
 
+        keyStoreUrl = null;
+        trustStoreUrl = null;
+
         trustStoreBytes = null;
         keyStoreBytes = null;
 
@@ -857,6 +917,9 @@
         trustStoreFile = AccessController.doPrivileged(PropertiesHelper.getSystemProperty(TRUST_STORE_FILE));
         keyStoreFile = AccessController.doPrivileged(PropertiesHelper.getSystemProperty(KEY_STORE_FILE));
 
+        trustStoreUrl = null;
+        keyStoreUrl = null;
+
         trustStoreBytes = null;
         keyStoreBytes = null;
 
@@ -876,91 +939,35 @@
         if (o == null || getClass() != o.getClass()) {
             return false;
         }
-
         SslConfigurator that = (SslConfigurator) o;
-
-        if (keyManagerFactoryAlgorithm != null
-                ? !keyManagerFactoryAlgorithm.equals(that.keyManagerFactoryAlgorithm) : that.keyManagerFactoryAlgorithm != null) {
-            return false;
-        }
-        if (keyManagerFactoryProvider != null
-                ? !keyManagerFactoryProvider.equals(that.keyManagerFactoryProvider) : that.keyManagerFactoryProvider != null) {
-            return false;
-        }
-        if (!Arrays.equals(keyPass, that.keyPass)) {
-            return false;
-        }
-        if (keyStore != null ? !keyStore.equals(that.keyStore) : that.keyStore != null) {
-            return false;
-        }
-        if (!Arrays.equals(keyStoreBytes, that.keyStoreBytes)) {
-            return false;
-        }
-        if (keyStoreFile != null ? !keyStoreFile.equals(that.keyStoreFile) : that.keyStoreFile != null) {
-            return false;
-        }
-        if (!Arrays.equals(keyStorePass, that.keyStorePass)) {
-            return false;
-        }
-        if (keyStoreProvider != null ? !keyStoreProvider.equals(that.keyStoreProvider) : that.keyStoreProvider != null) {
-            return false;
-        }
-        if (keyStoreType != null ? !keyStoreType.equals(that.keyStoreType) : that.keyStoreType != null) {
-            return false;
-        }
-        if (securityProtocol != null ? !securityProtocol.equals(that.securityProtocol) : that.securityProtocol != null) {
-            return false;
-        }
-        if (trustManagerFactoryAlgorithm != null ? !trustManagerFactoryAlgorithm.equals(that.trustManagerFactoryAlgorithm)
-                : that.trustManagerFactoryAlgorithm != null) {
-            return false;
-        }
-        if (trustManagerFactoryProvider != null ? !trustManagerFactoryProvider.equals(that.trustManagerFactoryProvider)
-                : that.trustManagerFactoryProvider != null) {
-            return false;
-        }
-        if (trustStore != null ? !trustStore.equals(that.trustStore) : that.trustStore != null) {
-            return false;
-        }
-        if (!Arrays.equals(trustStoreBytes, that.trustStoreBytes)) {
-            return false;
-        }
-        if (trustStoreFile != null ? !trustStoreFile.equals(that.trustStoreFile) : that.trustStoreFile != null) {
-            return false;
-        }
-        if (!Arrays.equals(trustStorePass, that.trustStorePass)) {
-            return false;
-        }
-        if (trustStoreProvider != null ? !trustStoreProvider.equals(that.trustStoreProvider) : that.trustStoreProvider != null) {
-            return false;
-        }
-        if (trustStoreType != null ? !trustStoreType.equals(that.trustStoreType) : that.trustStoreType != null) {
-            return false;
-        }
-
-        return true;
+        return Objects.equals(keyStore, that.keyStore)
+                && Objects.equals(trustStore, that.trustStore)
+                && Objects.equals(trustStoreProvider, that.trustStoreProvider)
+                && Objects.equals(keyStoreProvider, that.keyStoreProvider)
+                && Objects.equals(trustStoreType, that.trustStoreType)
+                && Objects.equals(keyStoreType, that.keyStoreType)
+                && Arrays.equals(trustStorePass, that.trustStorePass)
+                && Arrays.equals(keyStorePass, that.keyStorePass)
+                && Arrays.equals(keyPass, that.keyPass)
+                && Objects.equals(trustStoreFile, that.trustStoreFile)
+                && Objects.equals(keyStoreFile, that.keyStoreFile)
+                && Objects.equals(trustStoreUrl, that.trustStoreUrl)
+                && Objects.equals(keyStoreUrl, that.keyStoreUrl)
+                && Arrays.equals(trustStoreBytes, that.trustStoreBytes)
+                && Arrays.equals(keyStoreBytes, that.keyStoreBytes)
+                && Objects.equals(trustManagerFactoryAlgorithm, that.trustManagerFactoryAlgorithm)
+                && Objects.equals(keyManagerFactoryAlgorithm, that.keyManagerFactoryAlgorithm)
+                && Objects.equals(trustManagerFactoryProvider, that.trustManagerFactoryProvider)
+                && Objects.equals(keyManagerFactoryProvider, that.keyManagerFactoryProvider)
+                && Objects.equals(securityProtocol, that.securityProtocol);
     }
 
     @Override
     public int hashCode() {
-        int result = keyStore != null ? keyStore.hashCode() : 0;
-        result = 31 * result + (trustStore != null ? trustStore.hashCode() : 0);
-        result = 31 * result + (trustStoreProvider != null ? trustStoreProvider.hashCode() : 0);
-        result = 31 * result + (keyStoreProvider != null ? keyStoreProvider.hashCode() : 0);
-        result = 31 * result + (trustStoreType != null ? trustStoreType.hashCode() : 0);
-        result = 31 * result + (keyStoreType != null ? keyStoreType.hashCode() : 0);
-        result = 31 * result + (trustStorePass != null ? Arrays.hashCode(trustStorePass) : 0);
-        result = 31 * result + (keyStorePass != null ? Arrays.hashCode(keyStorePass) : 0);
-        result = 31 * result + (keyPass != null ? Arrays.hashCode(keyPass) : 0);
-        result = 31 * result + (trustStoreFile != null ? trustStoreFile.hashCode() : 0);
-        result = 31 * result + (keyStoreFile != null ? keyStoreFile.hashCode() : 0);
-        result = 31 * result + (trustStoreBytes != null ? Arrays.hashCode(trustStoreBytes) : 0);
-        result = 31 * result + (keyStoreBytes != null ? Arrays.hashCode(keyStoreBytes) : 0);
-        result = 31 * result + (trustManagerFactoryAlgorithm != null ? trustManagerFactoryAlgorithm.hashCode() : 0);
-        result = 31 * result + (keyManagerFactoryAlgorithm != null ? keyManagerFactoryAlgorithm.hashCode() : 0);
-        result = 31 * result + (trustManagerFactoryProvider != null ? trustManagerFactoryProvider.hashCode() : 0);
-        result = 31 * result + (keyManagerFactoryProvider != null ? keyManagerFactoryProvider.hashCode() : 0);
-        result = 31 * result + (securityProtocol != null ? securityProtocol.hashCode() : 0);
+        int result = Objects.hash(keyStore, trustStore, trustStoreProvider, keyStoreProvider, trustStoreType, keyStoreType,
+                trustStoreFile, keyStoreFile, trustStoreUrl, keyStoreUrl, trustManagerFactoryAlgorithm,
+                keyManagerFactoryAlgorithm, trustManagerFactoryProvider, keyManagerFactoryProvider, securityProtocol,
+                trustStorePass, keyStorePass, keyPass, trustStoreBytes, keyStoreBytes);
         return result;
     }
 }
diff --git a/core-common/src/main/java/org/glassfish/jersey/internal/config/JerseySystemPropertiesConfigurationModel.java b/core-common/src/main/java/org/glassfish/jersey/internal/config/JerseySystemPropertiesConfigurationModel.java
index 4d9606b..78a628d 100644
--- a/core-common/src/main/java/org/glassfish/jersey/internal/config/JerseySystemPropertiesConfigurationModel.java
+++ b/core-common/src/main/java/org/glassfish/jersey/internal/config/JerseySystemPropertiesConfigurationModel.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -29,6 +29,7 @@
             "org.glassfish.jersey.servlet.ServletProperties",
             "org.glassfish.jersey.message.MessageProperties",
             "org.glassfish.jersey.apache.connector.ApacheClientProperties",
+            "org.glassfish.jersey.apache5.connector.Apache5ClientProperties",
             "org.glassfish.jersey.helidon.connector.HelidonClientProperties",
             "org.glassfish.jersey.jdk.connector.JdkConnectorProperties",
             "org.glassfish.jersey.jetty.connector.JettyClientProperties",
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 9eb4a40..8f31f74 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -23,17 +23,13 @@
 import java.io.InputStream;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
-import java.net.URI;
 import java.text.ParseException;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.StringTokenizer;
@@ -41,21 +37,16 @@
 
 import jakarta.ws.rs.ProcessingException;
 import jakarta.ws.rs.core.Configuration;
-import jakarta.ws.rs.core.Cookie;
-import jakarta.ws.rs.core.EntityTag;
 import jakarta.ws.rs.core.HttpHeaders;
 import jakarta.ws.rs.core.Link;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.MultivaluedMap;
-import jakarta.ws.rs.core.NewCookie;
 import jakarta.ws.rs.ext.ReaderInterceptor;
 
-import jakarta.ws.rs.ext.RuntimeDelegate;
 import javax.xml.transform.Source;
 
 import org.glassfish.jersey.internal.LocalizationMessages;
 import org.glassfish.jersey.internal.PropertiesDelegate;
-import org.glassfish.jersey.internal.RuntimeDelegateDecorator;
 import org.glassfish.jersey.internal.util.collection.GuardianStringKeyMultivaluedMap;
 import org.glassfish.jersey.internal.util.collection.LazyValue;
 import org.glassfish.jersey.internal.util.collection.Value;
@@ -67,7 +58,7 @@
  *
  * @author Marek Potociar
  */
-public abstract class InboundMessageContext {
+public abstract class InboundMessageContext extends MessageHeaderMethods {
 
     private static final InputStream EMPTY = new InputStream() {
 
@@ -100,7 +91,6 @@
     private final boolean translateNce;
     private MessageBodyWorkers workers;
     private final Configuration configuration;
-    private final RuntimeDelegate runtimeDelegateDecorator;
     private LazyValue<MediaType> contentTypeCache;
     private LazyValue<List<AcceptableMediaType>> acceptTypeCache;
 
@@ -166,11 +156,11 @@
      *                      as required by JAX-RS specification on the server side.
      */
     public InboundMessageContext(Configuration configuration, boolean translateNce) {
+        super(configuration);
         this.headers = new GuardianStringKeyMultivaluedMap<>(HeaderUtils.createInbound());
         this.entityContent = new EntityContent();
         this.translateNce = translateNce;
         this.configuration = configuration;
-        runtimeDelegateDecorator = RuntimeDelegateDecorator.configured(configuration);
 
         contentTypeCache = contentTypeCache();
         acceptTypeCache = acceptTypeCache();
@@ -319,42 +309,9 @@
         return buffer.toString();
     }
 
-    /**
-     * Get a single typed header value.
-     *
-     * @param name        header name.
-     * @param converter   from string conversion function. Is expected to throw {@link ProcessingException}
-     *                    if conversion fails.
-     * @param convertNull if {@code true} this method calls the provided converter even for {@code null}. Otherwise this
-     *                    method returns the {@code null} without calling the converter.
-     * @return value of the header, or (possibly converted) {@code null} if not present.
-     */
-    private <T> T singleHeader(String name, Function<String, T> converter, boolean convertNull) {
-        final List<String> values = this.headers.get(name);
-
-        if (values == null || values.isEmpty()) {
-            return convertNull ? converter.apply(null) : null;
-        }
-        if (values.size() > 1) {
-            throw new HeaderValueException(LocalizationMessages.TOO_MANY_HEADER_VALUES(name, values.toString()),
-                    HeaderValueException.Context.INBOUND);
-        }
-
-        Object value = values.get(0);
-        if (value == null) {
-            return convertNull ? converter.apply(null) : null;
-        }
-
-        try {
-            return converter.apply(HeaderUtils.asString(value, runtimeDelegateDecorator));
-        } catch (ProcessingException ex) {
-            throw exception(name, value, ex);
-        }
-    }
-
-    private static HeaderValueException exception(final String headerName, Object headerValue, Exception e) {
-        return new HeaderValueException(LocalizationMessages.UNABLE_TO_PARSE_HEADER_VALUE(headerName, headerValue), e,
-                HeaderValueException.Context.INBOUND);
+    @Override
+    public HeaderValueException.Context getHeaderValueExceptionContext() {
+        return HeaderValueException.Context.INBOUND;
     }
 
     /**
@@ -367,24 +324,6 @@
     }
 
     /**
-     * Get message date.
-     *
-     * @return the message date, otherwise {@code null} if not present.
-     */
-    public Date getDate() {
-        return singleHeader(HttpHeaders.DATE, new Function<String, Date>() {
-            @Override
-            public Date apply(String input) {
-                try {
-                    return HttpHeaderReader.readDate(input);
-                } catch (ParseException ex) {
-                    throw new ProcessingException(ex);
-                }
-            }
-        }, false);
-    }
-
-    /**
      * Get If-Match header.
      *
      * @return the If-Match header value, otherwise {@code null} if not present.
@@ -419,42 +358,6 @@
     }
 
     /**
-     * Get the language of the entity.
-     *
-     * @return the language of the entity or {@code null} if not specified.
-     */
-    public Locale getLanguage() {
-        return singleHeader(HttpHeaders.CONTENT_LANGUAGE, new Function<String, Locale>() {
-            @Override
-            public Locale apply(String input) {
-                try {
-                    return new LanguageTag(input).getAsLocale();
-                } catch (ParseException e) {
-                    throw new ProcessingException(e);
-                }
-            }
-        }, false);
-    }
-
-    /**
-     * Get Content-Length value.
-     *
-     * @return Content-Length as integer if present and valid number. In other cases returns -1.
-     */
-    public int getLength() {
-        return singleHeader(HttpHeaders.CONTENT_LENGTH, new Function<String, Integer>() {
-            @Override
-            public Integer apply(String input) {
-                try {
-                    return (input != null && !input.isEmpty()) ? Integer.parseInt(input) : -1;
-                } catch (NumberFormatException ex) {
-                    throw new ProcessingException(ex);
-                }
-            }
-        }, true);
-    }
-
-    /**
      * Get the media type of the entity.
      *
      * @return the media type or {@code null} if not specified (e.g. there's no
@@ -569,120 +472,6 @@
     }
 
     /**
-     * Get any cookies that accompanied the request.
-     *
-     * @return a read-only map of cookie name (String) to {@link jakarta.ws.rs.core.Cookie}.
-     */
-    public Map<String, Cookie> getRequestCookies() {
-        List<String> cookies = this.headers.get(HttpHeaders.COOKIE);
-        if (cookies == null || cookies.isEmpty()) {
-            return Collections.emptyMap();
-        }
-
-        Map<String, Cookie> result = new HashMap<String, Cookie>();
-        for (String cookie : cookies) {
-            if (cookie != null) {
-                result.putAll(HttpHeaderReader.readCookies(cookie));
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Get the allowed HTTP methods from the Allow HTTP header.
-     *
-     * @return the allowed HTTP methods, all methods will returned as upper case
-     * strings.
-     */
-    public Set<String> getAllowedMethods() {
-        final String allowed = getHeaderString(HttpHeaders.ALLOW);
-        if (allowed == null || allowed.isEmpty()) {
-            return Collections.emptySet();
-        }
-        try {
-            return new HashSet<String>(HttpHeaderReader.readStringList(allowed.toUpperCase(Locale.ROOT)));
-        } catch (java.text.ParseException e) {
-            throw exception(HttpHeaders.ALLOW, allowed, e);
-        }
-    }
-
-    /**
-     * Get any new cookies set on the response message.
-     *
-     * @return a read-only map of cookie name (String) to a {@link jakarta.ws.rs.core.NewCookie new cookie}.
-     */
-    public Map<String, NewCookie> getResponseCookies() {
-        List<String> cookies = this.headers.get(HttpHeaders.SET_COOKIE);
-        if (cookies == null || cookies.isEmpty()) {
-            return Collections.emptyMap();
-        }
-
-        Map<String, NewCookie> result = new HashMap<String, NewCookie>();
-        for (String cookie : cookies) {
-            if (cookie != null) {
-                NewCookie newCookie = HttpHeaderReader.readNewCookie(cookie);
-                String cookieName = newCookie.getName();
-                if (result.containsKey(cookieName)) {
-                    result.put(cookieName, HeaderUtils.getPreferredCookie(result.get(cookieName), newCookie));
-                } else {
-                    result.put(cookieName, newCookie);
-                }
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Get the entity tag.
-     *
-     * @return the entity tag, otherwise {@code null} if not present.
-     */
-    public EntityTag getEntityTag() {
-        return singleHeader(HttpHeaders.ETAG, new Function<String, EntityTag>() {
-            @Override
-            public EntityTag apply(String value) {
-                return EntityTag.valueOf(value);
-            }
-        }, false);
-    }
-
-    /**
-     * Get the last modified date.
-     *
-     * @return the last modified date, otherwise {@code null} if not present.
-     */
-    public Date getLastModified() {
-        return singleHeader(HttpHeaders.LAST_MODIFIED, new Function<String, Date>() {
-            @Override
-            public Date apply(String input) {
-                try {
-                    return HttpHeaderReader.readDate(input);
-                } catch (ParseException e) {
-                    throw new ProcessingException(e);
-                }
-            }
-        }, false);
-    }
-
-    /**
-     * Get the location.
-     *
-     * @return the location URI, otherwise {@code null} if not present.
-     */
-    public URI getLocation() {
-        return singleHeader(HttpHeaders.LOCATION, new Function<String, URI>() {
-            @Override
-            public URI apply(String value) {
-                try {
-                    return URI.create(value);
-                } catch (IllegalArgumentException ex) {
-                    throw new ProcessingException(ex);
-                }
-            }
-        }, false);
-    }
-
-    /**
      * Get the links attached to the message as header.
      *
      * @return links, may return empty {@link java.util.Set} if no links are present. Never
@@ -726,57 +515,6 @@
         }
     }
 
-    /**
-     * Check if link for relation exists.
-     *
-     * @param relation link relation.
-     * @return {@code true} if the for the relation link exists, {@code false}
-     * otherwise.
-     */
-    public boolean hasLink(String relation) {
-        for (Link link : getLinks()) {
-            List<String> relations = LinkProvider.getLinkRelations(link.getRel());
-
-            if (relations != null && relations.contains(relation)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Get the link for the relation.
-     *
-     * @param relation link relation.
-     * @return the link for the relation, otherwise {@code null} if not present.
-     */
-    public Link getLink(String relation) {
-        for (Link link : getLinks()) {
-            List<String> relations = LinkProvider.getLinkRelations(link.getRel());
-            if (relations != null && relations.contains(relation)) {
-                return link;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Convenience method that returns a {@link jakarta.ws.rs.core.Link.Builder Link.Builder}
-     * for the relation.
-     *
-     * @param relation link relation.
-     * @return the link builder for the relation, otherwise {@code null} if not
-     * present.
-     */
-    public Link.Builder getLinkBuilder(String relation) {
-        Link link = getLink(relation);
-        if (link == null) {
-            return null;
-        }
-
-        return Link.fromLink(link);
-    }
-
     // Message entity
 
     /**
diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/MessageHeaderMethods.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/MessageHeaderMethods.java
new file mode 100644
index 0000000..cd23505
--- /dev/null
+++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/MessageHeaderMethods.java
@@ -0,0 +1,461 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.message.internal;
+
+import org.glassfish.jersey.internal.LocalizationMessages;
+import org.glassfish.jersey.internal.RuntimeDelegateDecorator;
+
+import jakarta.ws.rs.ProcessingException;
+import jakarta.ws.rs.core.Configuration;
+import jakarta.ws.rs.core.Cookie;
+import jakarta.ws.rs.core.EntityTag;
+import jakarta.ws.rs.core.HttpHeaders;
+import jakarta.ws.rs.core.Link;
+import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.core.NewCookie;
+import jakarta.ws.rs.ext.RuntimeDelegate;
+import java.net.URI;
+import java.text.ParseException;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+/**
+ * Common header methods for outbound and inbound messages.
+ */
+public abstract class MessageHeaderMethods {
+    protected RuntimeDelegate runtimeDelegateDecorator;
+
+    protected MessageHeaderMethods(Configuration configuration) {
+        this.runtimeDelegateDecorator = RuntimeDelegateDecorator.configured(configuration);
+    }
+
+    protected MessageHeaderMethods(MessageHeaderMethods other) {
+        this.runtimeDelegateDecorator = other.runtimeDelegateDecorator;
+    }
+
+    /**
+     * Get a message header as a single string value.
+     *
+     * Each single non-string header value is converted to String using a {@code RuntimeDelegate.HeaderDelegate} if one
+     * is available via {@code RuntimeDelegate#createHeaderDelegate(java.lang.Class)} for the header value
+     * class or using its {@code toString} method if a header delegate is not available.
+     *
+     * @param name the message header.
+     * @return the message header value. If the message header is not present then {@code null} is returned. If the message
+     * header is present but has no value then the empty string is returned. If the message header is present more than once
+     * then the values of joined together and separated by a ',' character.
+     */
+    public abstract String getHeaderString(String name);
+
+    /**
+     * Get the mutable message headers multivalued map.
+     *
+     * @return mutable multivalued map of message headers.
+     */
+    public abstract MultivaluedMap<String, ?> getHeaders();
+
+    /**
+     * Return {@link HeaderValueException.Context} type of the message context.
+     * @return {@link HeaderValueException.Context} type of the message context.
+     */
+    protected abstract HeaderValueException.Context getHeaderValueExceptionContext();
+
+    /**
+     * Get the links attached to the message as header.
+     *
+     * @return links, may return empty {@link java.util.Set} if no links are present. Never
+     * returns {@code null}.
+     */
+    public abstract Set<Link> getLinks();
+
+    /**
+     * Checks whether a header with a specific name and value (or item of the token-separated value list) exists.
+     *
+     * Each single non-string header value is converted to String using a {@code RuntimeDelegate.HeaderDelegate} if one
+     * is available via {@code RuntimeDelegate#createHeaderDelegate(java.lang.Class)} for the header value
+     * class or using its {@code toString} method if a header delegate is not available.
+     *
+     * <p>
+     * For example: {@code containsHeaderString("cache-control", ",", "no-store"::equalsIgnoreCase)} will return {@code true} if
+     * a {@code Cache-Control} header exists that has the value {@code no-store}, the value {@code No-Store} or the value
+     * {@code Max-Age, NO-STORE, no-transform}, but {@code false} when it has the value {@code no-store;no-transform}
+     * (missing comma), or the value {@code no - store} (whitespace within value).
+     *
+     * @param name the message header.
+     * @param valueSeparatorRegex Separates the header value into single values. {@code null} does not split.
+     * @param valuePredicate value must fulfil this predicate.
+     * @return {@code true} if and only if a header with the given name exists, having either a whitespace-trimmed value
+     * matching the predicate, or having at least one whitespace-trimmed single value in a token-separated list of single values.
+     */
+    public boolean containsHeaderString(String name, String valueSeparatorRegex, Predicate<String> valuePredicate) {
+        final String header = getHeaderString(name);
+        if (header == null) {
+            return false;
+        }
+        final String[] split = header.split(valueSeparatorRegex);
+        for (String s : split) {
+            if (valuePredicate.test(s.trim())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Checks whether a header with a specific name and value (or item of the comma-separated value list) exists.
+     *
+     * Each single non-string header value is converted to String using a {@code RuntimeDelegate.HeaderDelegate} if one
+     * is available via {@code RuntimeDelegate#createHeaderDelegate(java.lang.Class)} for the header value
+     * class or using its {@code toString} method if a header delegate is not available.
+     *
+     * <p>
+     * For example: {@code containsHeaderString("cache-control", "no-store"::equalsIgnoreCase)} will return {@code true} if
+     * a {@code Cache-Control} header exists that has the value {@code no-store}, the value {@code No-Store} or the value
+     * {@code Max-Age, NO-STORE, no-transform}, but {@code false} when it has the value {@code no-store;no-transform}
+     * (missing comma), or the value {@code no - store} (whitespace within value).
+     *
+     * @param name the message header.
+     * @param valuePredicate value must fulfil this predicate.
+     * @return {@code true} if and only if a header with the given name exists, having either a whitespace-trimmed value
+     * matching the predicate, or having at least one whitespace-trimmed single value in a comma-separated list of single values.
+     */
+    public boolean containsHeaderString(String name, Predicate<String> valuePredicate) {
+        return containsHeaderString(name, ",", valuePredicate);
+    }
+
+    /**
+     * Get the allowed HTTP methods from the Allow HTTP header.
+     *
+     * @return the allowed HTTP methods, all methods will returned as upper case
+     * strings.
+     */
+    public Set<String> getAllowedMethods() {
+        final String allowed = getHeaderString(HttpHeaders.ALLOW);
+        if (allowed == null || allowed.isEmpty()) {
+            return Collections.emptySet();
+        }
+        try {
+            return new HashSet<String>(HttpHeaderReader.readStringList(allowed.toUpperCase(Locale.ROOT)));
+        } catch (java.text.ParseException e) {
+            throw exception(HttpHeaders.ALLOW, allowed, e);
+        }
+    }
+
+    /**
+     * Get message date.
+     *
+     * @return the message date, otherwise {@code null} if not present.
+     */
+    public Date getDate() {
+        return singleHeader(HttpHeaders.DATE, Date.class, input -> {
+            try {
+                return HttpHeaderReader.readDate(input);
+            } catch (ParseException e) {
+                throw new ProcessingException(e);
+            }
+        }, false);
+    }
+
+    /**
+     * Get the entity tag.
+     *
+     * @return the entity tag, otherwise {@code null} if not present.
+     */
+    public EntityTag getEntityTag() {
+        return singleHeader(HttpHeaders.ETAG, EntityTag.class, new Function<String, EntityTag>() {
+            @Override
+            public EntityTag apply(String value) {
+                try {
+                    return value == null ? null : EntityTag.valueOf(value);
+                } catch (IllegalArgumentException ex) {
+                    throw new ProcessingException(ex);
+                }
+            }
+        }, false);
+    }
+
+    /**
+     * Get the language of the entity.
+     *
+     * @return the language of the entity or {@code null} if not specified
+     */
+    public Locale getLanguage() {
+        return singleHeader(HttpHeaders.CONTENT_LANGUAGE, Locale.class, input -> {
+            try {
+                return new LanguageTag(input).getAsLocale();
+            } catch (ParseException e) {
+                throw new ProcessingException(e);
+            }
+        }, false);
+    }
+
+    /**
+     * Get the last modified date.
+     *
+     * @return the last modified date, otherwise {@code null} if not present.
+     */
+    public Date getLastModified() {
+        return singleHeader(HttpHeaders.LAST_MODIFIED, Date.class, new Function<String, Date>() {
+            @Override
+            public Date apply(String input) {
+                try {
+                    return HttpHeaderReader.readDate(input);
+                } catch (ParseException e) {
+                    throw new ProcessingException(e);
+                }
+            }
+        }, false);
+    }
+
+    /**
+     * Get Content-Length value.
+     * <p>
+     * <B>Note</B>: {@link #getLengthLong() getLengthLong()}
+     * should be preferred over this method, since it returns a {@code long}
+     * instead and is therefore more portable.</P>
+     *
+     * @return Content-Length as a postive integer if present and valid number, {@code -1} if negative number.
+     * @throws ProcessingException when {@link Integer#parseInt(String)} (String)} throws {@link NumberFormatException}.
+     */
+    public int getLength() {
+        return singleHeader(HttpHeaders.CONTENT_LENGTH, Integer.class, input -> {
+            try {
+                if (input != null && !input.isEmpty()) {
+                    int i = Integer.parseInt(input);
+                    if (i >= 0) {
+                        return i;
+                    }
+                }
+                return -1;
+
+            } catch (NumberFormatException ex) {
+                throw new ProcessingException(ex);
+            }
+        }, true);
+    }
+
+    /**
+     * Get Content-Length value.
+     *
+     * @return Content-Length as a positive long if present and valid number, {@code -1} if negative number.
+     * @throws ProcessingException when {@link Long#parseLong(String)} throws {@link NumberFormatException}.
+     */
+    public long getLengthLong() {
+        return singleHeader(HttpHeaders.CONTENT_LENGTH, Long.class, input -> {
+            try {
+                if (input != null && !input.isEmpty()) {
+                    long l = Long.parseLong(input);
+                    if (l >= 0) {
+                        return l;
+                    }
+                }
+                return -1L;
+            } catch (NumberFormatException ex) {
+                throw new ProcessingException(ex);
+            }
+        }, true);
+    }
+
+    /**
+     * Get the link for the relation.
+     *
+     * @param relation link relation.
+     * @return the link for the relation, otherwise {@code null} if not present.
+     */
+    public Link getLink(String relation) {
+        for (Link link : getLinks()) {
+            List<String> relations = LinkProvider.getLinkRelations(link.getRel());
+            if (relations != null && relations.contains(relation)) {
+                return link;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Convenience method that returns a {@link jakarta.ws.rs.core.Link.Builder Link.Builder}
+     * for the relation.
+     *
+     * @param relation link relation.
+     * @return the link builder for the relation, otherwise {@code null} if not
+     * present.
+     */
+    public Link.Builder getLinkBuilder(String relation) {
+        Link link = getLink(relation);
+        if (link == null) {
+            return null;
+        }
+
+        return Link.fromLink(link);
+    }
+
+    /**
+     * Get the location.
+     *
+     * @return the location URI, otherwise {@code null} if not present.
+     */
+    public URI getLocation() {
+        return singleHeader(HttpHeaders.LOCATION, URI.class, value -> {
+            try {
+                return value == null ? null : URI.create(value);
+            } catch (IllegalArgumentException ex) {
+                throw new ProcessingException(ex);
+            }
+        }, false);
+    }
+
+    /**
+     * Get any cookies that accompanied the message.
+     *
+     * @return a read-only map of cookie name (String) to {@link jakarta.ws.rs.core.Cookie}.
+     */
+    public Map<String, Cookie> getRequestCookies() {
+        @SuppressWarnings("unchecked")
+        final List<Object> cookies = (List<Object>) getHeaders().get(HttpHeaders.COOKIE);
+        if (cookies == null || cookies.isEmpty()) {
+            return Collections.emptyMap();
+        }
+
+        Map<String, Cookie> result = new HashMap<String, Cookie>();
+        for (String cookie : toStringList(cookies)) {
+            if (cookie != null) {
+                result.putAll(HttpHeaderReader.readCookies(cookie));
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Get any new cookies set on the message.
+     *
+     * @return a read-only map of cookie name (String) to a {@link jakarta.ws.rs.core.NewCookie new cookie}.
+     */
+    public Map<String, NewCookie> getResponseCookies() {
+        @SuppressWarnings("unchecked")
+        List<Object> cookies = (List<Object>) getHeaders().get(HttpHeaders.SET_COOKIE);
+        if (cookies == null || cookies.isEmpty()) {
+            return Collections.emptyMap();
+        }
+
+        Map<String, NewCookie> result = new HashMap<String, NewCookie>();
+        for (String cookie : toStringList(cookies)) {
+            if (cookie != null) {
+                NewCookie newCookie = HttpHeaderReader.readNewCookie(cookie);
+                String cookieName = newCookie.getName();
+                if (result.containsKey(cookieName)) {
+                    result.put(cookieName, HeaderUtils.getPreferredCookie(result.get(cookieName), newCookie));
+                } else {
+                    result.put(cookieName, newCookie);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Check if link for relation exists.
+     *
+     * @param relation link relation.
+     * @return {@code true} if the for the relation link exists, {@code false}
+     * otherwise.
+     */
+    public boolean hasLink(String relation) {
+        for (Link link : getLinks()) {
+            List<String> relations = LinkProvider.getLinkRelations(link.getRel());
+
+            if (relations != null && relations.contains(relation)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Get a single typed header value.
+     *
+     * @param <T>         header value type.
+     * @param name        header name.
+     * @param valueType   header value class.
+     * @param converter   from string conversion function. Is expected to throw {@link ProcessingException}
+     *                    if conversion fails.
+     * @param convertNull if {@code true} this method calls the provided converter even for {@code null}. Otherwise this
+     *                    method returns the {@code null} without calling the converter.
+     * @return value of the header, or (possibly converted) {@code null} if not present.
+     */
+    protected <T> T singleHeader(String name, Class<T> valueType, Function<String, T> converter, boolean convertNull) {
+        @SuppressWarnings("unchecked")
+        final List<Object> values = (List<Object>) getHeaders().get(name);
+
+        if (values == null || values.isEmpty()) {
+            return convertNull ? converter.apply(null) : null;
+        }
+        if (values.size() > 1) {
+            throw new HeaderValueException(
+                    LocalizationMessages.TOO_MANY_HEADER_VALUES(name, values.toString()),
+                    getHeaderValueExceptionContext());
+        }
+
+        Object value = values.get(0);
+        if (value == null) {
+            return convertNull ? converter.apply(null) : null;
+        }
+
+        if (HeaderValueException.Context.OUTBOUND == getHeaderValueExceptionContext() && valueType.isInstance(value)) {
+            return valueType.cast(value);
+        } else {
+            try {
+                return converter.apply(HeaderUtils.asString(value, runtimeDelegateDecorator));
+            } catch (ProcessingException ex) {
+                throw exception(name, value, ex);
+            }
+        }
+    }
+
+    /**
+     * Get a single typed header value for Inbound messages
+     *
+     * @param <T>         header value type.
+     * @param name        header name.
+     * @param converter   from string conversion function. Is expected to throw {@link ProcessingException}
+     *                    if conversion fails.
+     * @param convertNull if {@code true} this method calls the provided converter even for {@code null}. Otherwise this
+     *                    method returns the {@code null} without calling the converter.
+     * @return value of the header, or (possibly converted) {@code null} if not present.
+     */
+    protected <T> T singleHeader(String name, Function<String, T> converter, boolean convertNull) {
+        return singleHeader(name, null, converter, convertNull);
+    }
+
+    protected HeaderValueException exception(final String headerName, Object headerValue, Exception e) {
+        return new HeaderValueException(LocalizationMessages.UNABLE_TO_PARSE_HEADER_VALUE(headerName, headerValue), e,
+                getHeaderValueExceptionContext());
+    }
+
+    private List<String> toStringList(List list) {
+        return getHeaderValueExceptionContext() == HeaderValueException.Context.OUTBOUND
+                ? HeaderUtils.asStringList(list, runtimeDelegateDecorator)
+                : (List<String>) list;
+    }
+}
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 d33acc3..c69f173 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -20,38 +20,27 @@
 import java.io.OutputStream;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
-import java.net.URI;
-import java.text.ParseException;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
 import java.util.Set;
 import java.util.function.Function;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
 
-import jakarta.ws.rs.ProcessingException;
 import jakarta.ws.rs.core.Configuration;
-import jakarta.ws.rs.core.Cookie;
-import jakarta.ws.rs.core.EntityTag;
 import jakarta.ws.rs.core.GenericEntity;
 import jakarta.ws.rs.core.GenericType;
 import jakarta.ws.rs.core.HttpHeaders;
 import jakarta.ws.rs.core.Link;
 import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.MultivaluedMap;
-import jakarta.ws.rs.core.NewCookie;
-import jakarta.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;
 import org.glassfish.jersey.internal.util.collection.GuardianStringKeyMultivaluedMap;
 import org.glassfish.jersey.internal.util.collection.LazyValue;
@@ -63,7 +52,7 @@
  *
  * @author Marek Potociar
  */
-public class OutboundMessageContext {
+public class OutboundMessageContext extends MessageHeaderMethods {
     private static final Annotation[] EMPTY_ANNOTATIONS = new Annotation[0];
     private static final List<MediaType> WILDCARD_ACCEPTABLE_TYPE_SINGLETON_LIST =
             Collections.<MediaType>singletonList(MediaTypes.WILDCARD_ACCEPTABLE_TYPE);
@@ -71,7 +60,6 @@
     private final GuardianStringKeyMultivaluedMap<Object> headers;
     private final CommittingOutputStream committingOutputStream;
     private Configuration configuration;
-    private RuntimeDelegate runtimeDelegateDecorator;
     private LazyValue<MediaType> mediaTypeCache;
 
     private Object entity;
@@ -107,11 +95,11 @@
      * @param configuration the client/server {@link Configuration}. If {@code null}, the default behaviour is expected.
      */
     public OutboundMessageContext(Configuration configuration) {
+        super(configuration);
         this.configuration = configuration;
         this.headers = new GuardianStringKeyMultivaluedMap<>(HeaderUtils.createOutbound());
         this.committingOutputStream = new CommittingOutputStream();
         this.entityStream = committingOutputStream;
-        this.runtimeDelegateDecorator = RuntimeDelegateDecorator.configured(configuration);
         this.mediaTypeCache = mediaTypeCache();
 
         headers.setGuard(HttpHeaders.CONTENT_TYPE);
@@ -124,6 +112,7 @@
      * @param original the original outbound message context.
      */
     public OutboundMessageContext(OutboundMessageContext original) {
+        super(original);
         this.headers = new GuardianStringKeyMultivaluedMap<>(HeaderUtils.createOutbound());
         this.headers.setGuard(HttpHeaders.CONTENT_TYPE);
         this.headers.putAll(original.headers);
@@ -134,7 +123,6 @@
         this.entityType = original.entityType;
         this.entityAnnotations = original.entityAnnotations;
         this.configuration = original.configuration;
-        this.runtimeDelegateDecorator = original.runtimeDelegateDecorator;
         this.mediaTypeCache = mediaTypeCache();
     }
 
@@ -190,49 +178,9 @@
         return HeaderUtils.asHeaderString(headers.get(name), runtimeDelegateDecorator);
     }
 
-    /**
-     * Get a single typed header value.
-     *
-     * @param <T>         header value type.
-     * @param name        header name.
-     * @param valueType   header value class.
-     * @param converter   from string conversion function. Is expected to throw {@link ProcessingException}
-     *                    if conversion fails.
-     * @param convertNull if {@code true} this method calls the provided converter even for {@code null}. Otherwise this
-     *                    method returns the {@code null} without calling the converter.
-     * @return value of the header, or (possibly converted) {@code null} if not present.
-     */
-    private <T> T singleHeader(String name, Class<T> valueType, Function<String, T> converter, boolean convertNull) {
-        final List<Object> values = headers.get(name);
-
-        if (values == null || values.isEmpty()) {
-            return convertNull ? converter.apply(null) : null;
-        }
-        if (values.size() > 1) {
-            throw new HeaderValueException(
-                    LocalizationMessages.TOO_MANY_HEADER_VALUES(name, values.toString()),
-                    HeaderValueException.Context.OUTBOUND);
-        }
-
-        Object value = values.get(0);
-        if (value == null) {
-            return convertNull ? converter.apply(null) : null;
-        }
-
-        if (valueType.isInstance(value)) {
-            return valueType.cast(value);
-        } else {
-            try {
-                return converter.apply(HeaderUtils.asString(value, runtimeDelegateDecorator));
-            } catch (ProcessingException ex) {
-                throw exception(name, value, ex);
-            }
-        }
-    }
-
-    private static HeaderValueException exception(final String headerName, Object headerValue, Exception e) {
-        return new HeaderValueException(LocalizationMessages.UNABLE_TO_PARSE_HEADER_VALUE(headerName, headerValue), e,
-                HeaderValueException.Context.OUTBOUND);
+    @Override
+    public HeaderValueException.Context getHeaderValueExceptionContext() {
+        return HeaderValueException.Context.OUTBOUND;
     }
 
     /**
@@ -245,36 +193,6 @@
     }
 
     /**
-     * Get message date.
-     *
-     * @return the message date, otherwise {@code null} if not present.
-     */
-    public Date getDate() {
-        return singleHeader(HttpHeaders.DATE, Date.class, input -> {
-            try {
-                return HttpHeaderReader.readDate(input);
-            } catch (ParseException e) {
-                throw new ProcessingException(e);
-            }
-        }, false);
-    }
-
-    /**
-     * Get the language of the entity.
-     *
-     * @return the language of the entity or {@code null} if not specified
-     */
-    public Locale getLanguage() {
-        return singleHeader(HttpHeaders.CONTENT_LANGUAGE, Locale.class, input -> {
-            try {
-                return new LanguageTag(input).getAsLocale();
-            } catch (ParseException e) {
-                throw new ProcessingException(e);
-            }
-        }, false);
-    }
-
-    /**
      * Get the media type of the entity.
      *
      * @return the media type or {@code null} if not specified (e.g. there's no
@@ -378,174 +296,6 @@
     }
 
     /**
-     * Get any cookies that accompanied the message.
-     *
-     * @return a read-only map of cookie name (String) to {@link jakarta.ws.rs.core.Cookie}.
-     */
-    public Map<String, Cookie> getRequestCookies() {
-        final List<Object> cookies = headers.get(HttpHeaders.COOKIE);
-        if (cookies == null || cookies.isEmpty()) {
-            return Collections.emptyMap();
-        }
-
-        Map<String, Cookie> result = new HashMap<String, Cookie>();
-        for (String cookie : HeaderUtils.asStringList(cookies, runtimeDelegateDecorator)) {
-            if (cookie != null) {
-                result.putAll(HttpHeaderReader.readCookies(cookie));
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Get the allowed HTTP methods from the Allow HTTP header.
-     *
-     * @return the allowed HTTP methods, all methods will returned as upper case
-     * strings.
-     */
-    public Set<String> getAllowedMethods() {
-        final String allowed = getHeaderString(HttpHeaders.ALLOW);
-        if (allowed == null || allowed.isEmpty()) {
-            return Collections.emptySet();
-        }
-        try {
-            return new HashSet<String>(HttpHeaderReader.readStringList(allowed));
-        } catch (java.text.ParseException e) {
-            throw exception(HttpHeaders.ALLOW, allowed, e);
-        }
-    }
-
-    /**
-     * Get Content-Length value.
-     * <p>
-     * <B>Note</B>: {@link #getLengthLong() getLengthLong()}
-     * should be preferred over this method, since it returns a {@code long}
-     * instead and is therefore more portable.</P>
-     *
-     * @return Content-Length as a postive integer if present and valid number, {@code -1} if negative number.
-     * @throws ProcessingException when {@link Integer#parseInt(String)} (String)} throws {@link NumberFormatException}.
-     */
-    public int getLength() {
-
-        return singleHeader(HttpHeaders.CONTENT_LENGTH, Integer.class, input -> {
-            try {
-                if (input != null && !input.isEmpty()) {
-                    int i = Integer.parseInt(input);
-                    if (i >= 0) {
-                        return i;
-                    }
-                }
-                return -1;
-
-            } catch (NumberFormatException ex) {
-                throw new ProcessingException(ex);
-            }
-        }, true);
-    }
-
-    /**
-     * Get Content-Length value.
-     *
-     * @return Content-Length as a positive long if present and valid number, {@code -1} if negative number.
-     * @throws ProcessingException when {@link Long#parseLong(String)} throws {@link NumberFormatException}.
-     */
-    public long getLengthLong() {
-        return singleHeader(HttpHeaders.CONTENT_LENGTH, Long.class, input -> {
-            try {
-                if (input != null && !input.isEmpty()) {
-                    long l = Long.parseLong(input);
-                    if (l >= 0) {
-                        return l;
-                    }
-                }
-                return -1L;
-            } catch (NumberFormatException ex) {
-                throw new ProcessingException(ex);
-            }
-        }, true);
-    }
-
-    /**
-     * Get any new cookies set on the message message.
-     *
-     * @return a read-only map of cookie name (String) to a {@link jakarta.ws.rs.core.NewCookie new cookie}.
-     */
-    public Map<String, NewCookie> getResponseCookies() {
-        List<Object> cookies = headers.get(HttpHeaders.SET_COOKIE);
-        if (cookies == null || cookies.isEmpty()) {
-            return Collections.emptyMap();
-        }
-
-        Map<String, NewCookie> result = new HashMap<String, NewCookie>();
-        for (String cookie : HeaderUtils.asStringList(cookies, runtimeDelegateDecorator)) {
-            if (cookie != null) {
-                NewCookie newCookie = HttpHeaderReader.readNewCookie(cookie);
-                String cookieName = newCookie.getName();
-                if (result.containsKey(cookieName)) {
-                    result.put(cookieName, HeaderUtils.getPreferredCookie(result.get(cookieName), newCookie));
-                } else {
-                    result.put(cookieName, newCookie);
-                }
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Get the entity tag.
-     *
-     * @return the entity tag, otherwise {@code null} if not present.
-     */
-    public EntityTag getEntityTag() {
-        return singleHeader(HttpHeaders.ETAG, EntityTag.class, new Function<String, EntityTag>() {
-            @Override
-            public EntityTag apply(String value) {
-                try {
-                    return value == null ? null : EntityTag.valueOf(value);
-                } catch (IllegalArgumentException ex) {
-                    throw new ProcessingException(ex);
-                }
-            }
-        }, false);
-    }
-
-    /**
-     * Get the last modified date.
-     *
-     * @return the last modified date, otherwise {@code null} if not present.
-     */
-    public Date getLastModified() {
-        return singleHeader(HttpHeaders.LAST_MODIFIED, Date.class, new Function<String, Date>() {
-            @Override
-            public Date apply(String input) {
-                try {
-                    return HttpHeaderReader.readDate(input);
-                } catch (ParseException e) {
-                    throw new ProcessingException(e);
-                }
-            }
-        }, false);
-    }
-
-    /**
-     * Get the location.
-     *
-     * @return the location URI, otherwise {@code null} if not present.
-     */
-    public URI getLocation() {
-        return singleHeader(HttpHeaders.LOCATION, URI.class, new Function<String, URI>() {
-            @Override
-            public URI apply(String value) {
-                try {
-                    return value == null ? null : URI.create(value);
-                } catch (IllegalArgumentException ex) {
-                    throw new ProcessingException(ex);
-                }
-            }
-        }, false);
-    }
-
-    /**
      * Get the links attached to the message as header.
      *
      * @return links, may return empty {@link java.util.Set} if no links are present. Never
@@ -583,56 +333,6 @@
         return Collections.unmodifiableSet(result);
     }
 
-    /**
-     * Check if link for relation exists.
-     *
-     * @param relation link relation.
-     * @return {@code true} if the for the relation link exists, {@code false}
-     * otherwise.
-     */
-    public boolean hasLink(String relation) {
-        for (Link link : getLinks()) {
-            List<String> relations = LinkProvider.getLinkRelations(link.getRel());
-            if (relations != null && relations.contains(relation)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Get the link for the relation.
-     *
-     * @param relation link relation.
-     * @return the link for the relation, otherwise {@code null} if not present.
-     */
-    public Link getLink(String relation) {
-        for (Link link : getLinks()) {
-            List<String> relations = LinkProvider.getLinkRelations(link.getRel());
-            if (relations != null && relations.contains(relation)) {
-                return link;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Convenience method that returns a {@link jakarta.ws.rs.core.Link.Builder Link.Builder}
-     * for the relation.
-     *
-     * @param relation link relation.
-     * @return the link builder for the relation, otherwise {@code null} if not
-     * present.
-     */
-    public Link.Builder getLinkBuilder(String relation) {
-        Link link = getLink(relation);
-        if (link == null) {
-            return null;
-        }
-
-        return Link.fromLink(link);
-    }
-
     // Message entity
 
     /**
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ServerRuntime.java b/core-server/src/main/java/org/glassfish/jersey/server/ServerRuntime.java
index 6c5740e..04d820d 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/ServerRuntime.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/ServerRuntime.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -526,7 +526,7 @@
                         processingContext.routingContext().setMappedThrowable(throwable);
 
                         waeResponse = webApplicationException.getResponse();
-                        if (waeResponse.hasEntity()) {
+                        if (waeResponse != null && waeResponse.hasEntity()) {
                             LOGGER.log(Level.FINE, LocalizationMessages
                                     .EXCEPTION_MAPPING_WAE_ENTITY(waeResponse.getStatus()), throwable);
                             return waeResponse;
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/JarZipSchemeResourceFinderFactory.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/JarZipSchemeResourceFinderFactory.java
index aa2874e..f08cfb1 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/JarZipSchemeResourceFinderFactory.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/scanning/JarZipSchemeResourceFinderFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -16,13 +16,13 @@
 
 package org.glassfish.jersey.server.internal.scanning;
 
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URL;
 import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
@@ -155,7 +155,7 @@
             return new URL(jarUrlString).openStream();
         } catch (final MalformedURLException e) {
             return Files.newInputStream(
-                    new File(UriComponent.decode(jarUrlString, UriComponent.Type.PATH)).toPath());
+                    Paths.get(UriComponent.decode(jarUrlString, UriComponent.Type.PATH)));
         }
     }
 }
diff --git a/examples/NOTICE.md b/examples/NOTICE.md
index aafa80c..89e2821 100644
--- a/examples/NOTICE.md
+++ b/examples/NOTICE.md
@@ -71,7 +71,7 @@
 * Project: http://www.javassist.org/
 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
 
-Jackson JAX-RS Providers Version 2.15.3
+Jackson JAX-RS Providers Version 2.16.1
 * License: Apache License, 2.0
 * Project: https://github.com/FasterXML/jackson-jaxrs-providers
 * Copyright: (c) 2009-2023 FasterXML, LLC. All rights reserved unless otherwise indicated.
diff --git a/ext/mvc/src/main/java/org/glassfish/jersey/server/mvc/spi/AbstractTemplateProcessor.java b/ext/mvc/src/main/java/org/glassfish/jersey/server/mvc/spi/AbstractTemplateProcessor.java
index ed0c590..79dd79c 100644
--- a/ext/mvc/src/main/java/org/glassfish/jersey/server/mvc/spi/AbstractTemplateProcessor.java
+++ b/ext/mvc/src/main/java/org/glassfish/jersey/server/mvc/spi/AbstractTemplateProcessor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -16,13 +16,13 @@
 
 package org.glassfish.jersey.server.mvc.spi;
 
-import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.Reader;
 import java.nio.charset.Charset;
 import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -182,7 +182,7 @@
             // File-system path.
             if (reader == null) {
                 try {
-                    reader = new InputStreamReader(Files.newInputStream(new File(template).toPath()), encoding);
+                    reader = new InputStreamReader(Files.newInputStream(Paths.get(template)), encoding);
                 } catch (final IOException ioe) {
                     // NOOP.
                 }
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java
index f715407..b11c121 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/DefaultJacksonJaxbJsonProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -129,7 +129,11 @@
             final StreamReadConstraints constraints = jsonFactory.streamReadConstraints();
             jsonFactory.setStreamReadConstraints(
                     StreamReadConstraints.builder()
+                            // our
                             .maxStringLength(maxStringLength)
+                            // customers
+                            .maxDocumentLength(constraints.getMaxDocumentLength())
+                            .maxNameLength(constraints.getMaxNameLength())
                             .maxNestingDepth(constraints.getMaxNestingDepth())
                             .maxNumberLength(constraints.getMaxNumberLength())
                             .build()
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/JacksonObjectProvider.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/JacksonObjectProvider.java
index a12d4d0..74f510c 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/JacksonObjectProvider.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/JacksonObjectProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -26,6 +26,7 @@
 import org.glassfish.jersey.message.filtering.spi.EntityGraphProvider;
 import org.glassfish.jersey.message.filtering.spi.EntityInspector;
 import org.glassfish.jersey.message.filtering.spi.ObjectGraph;
+import org.glassfish.jersey.message.filtering.spi.ScopeProvider;
 
 import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.databind.JsonMappingException;
@@ -37,7 +38,6 @@
 import com.fasterxml.jackson.databind.ser.PropertyFilter;
 import com.fasterxml.jackson.databind.ser.PropertyWriter;
 import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
-import org.glassfish.jersey.message.filtering.spi.ScopeProvider;
 
 import jakarta.inject.Inject;
 import jakarta.ws.rs.core.Context;
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/base/ProviderBase.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/base/ProviderBase.java
index ecdfbae..bf365bb 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/base/ProviderBase.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/base/ProviderBase.java
@@ -31,7 +31,6 @@
 import org.glassfish.jersey.jackson.internal.jackson.jaxrs.cfg.ObjectWriterInjector;
 import org.glassfish.jersey.jackson.internal.jackson.jaxrs.cfg.ObjectWriterModifier;
 import org.glassfish.jersey.jackson.internal.jackson.jaxrs.util.ClassKey;
-import org.glassfish.jersey.jackson.internal.jackson.jaxrs.util.LRUMap;
 
 import com.fasterxml.jackson.core.JsonEncoding;
 import com.fasterxml.jackson.core.JsonGenerator;
@@ -44,6 +43,7 @@
 import com.fasterxml.jackson.databind.ObjectReader;
 import com.fasterxml.jackson.databind.ObjectWriter;
 import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.util.LRUMap;
 import com.fasterxml.jackson.databind.type.TypeFactory;
 
 public abstract class ProviderBase<
@@ -1056,4 +1056,4 @@
     private final THIS _this() {
         return (THIS) this;
     }
-}
\ No newline at end of file
+}
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/cfg/JaxRSFeature.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/cfg/JaxRSFeature.java
index 6f864c9..c0f0da5 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/cfg/JaxRSFeature.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/cfg/JaxRSFeature.java
@@ -40,6 +40,7 @@
      * @since 2.15
      */
     READ_FULL_STREAM(true),
+
     /*
     /**********************************************************
     /* HTTP headers
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/PackageVersion.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/PackageVersion.java
index 3a34c28..61edeb7 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/PackageVersion.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/json/PackageVersion.java
@@ -11,7 +11,7 @@
  */
 public final class PackageVersion implements Versioned {
     public final static Version VERSION = VersionUtil.parseVersion(
-        "2.15.3", "com.fasterxml.jackson.jaxrs", "jackson-jaxrs-json-provider");
+        "2.16.1", "com.fasterxml.jackson.jaxrs", "jackson-jaxrs-json-provider");
 
     @Override
     public Version version() {
diff --git a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/util/LRUMap.java b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/util/LRUMap.java
index 7252cd5..c99c987 100644
--- a/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/util/LRUMap.java
+++ b/media/json-jackson/src/main/java/org/glassfish/jersey/jackson/internal/jackson/jaxrs/util/LRUMap.java
@@ -3,11 +3,15 @@
 import java.util.LinkedHashMap;
 import java.util.Map;
 
+// TO BE REMOVED FROM JACKSON 2.18 or later
 /**
  * Helper for simple bounded LRU maps used for reusing lookup values.
  *
  * @since 2.2
+ *
+ * @deprecated Since 2.16.1 Use one from {@code jackson-databind} instead.
  */
+@Deprecated // since 2.16.1
 @SuppressWarnings("serial")
 public class LRUMap<K,V> extends LinkedHashMap<K,V>
 {
@@ -24,5 +28,4 @@
     {
         return size() > _maxEntries;
     }
-
 }
diff --git a/media/json-jackson/src/main/resources/META-INF/NOTICE.markdown b/media/json-jackson/src/main/resources/META-INF/NOTICE.markdown
index 4251b2f..5b5dcd7 100644
--- a/media/json-jackson/src/main/resources/META-INF/NOTICE.markdown
+++ b/media/json-jackson/src/main/resources/META-INF/NOTICE.markdown
@@ -31,7 +31,7 @@
 

 ## Third-party Content

 

-Jackson JAX-RS Providers version 2.15.3

+Jackson JAX-RS Providers version 2.16.1

 * License: Apache License, 2.0

 * Project: https://github.com/FasterXML/jackson-jaxrs-providers

 * Copyright: (c) 2009-2023 FasterXML, LLC. All rights reserved unless otherwise indicated.

diff --git a/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForDisabledModulesTest.java b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForDisabledModulesTest.java
index e75400a..3e40866 100644
--- a/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForDisabledModulesTest.java
+++ b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForDisabledModulesTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -30,6 +30,7 @@
 import jakarta.ws.rs.core.Application;
 import jakarta.ws.rs.core.Configuration;
 import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.Response;
 
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -48,9 +49,10 @@
                 .register(JacksonFeature.class)
                 .register(TestJacksonJaxbJsonProvider.class)
                 .property("jersey.config.json.jackson.disabled.modules", "Jdk8Module");
-        final String response = target("JAXBEntity")
-                .request().get(String.class);
-        assertNotEquals("{\"key\":\"key\",\"value\":\"value\"}", response);
+        try (Response response = target("JAXBEntity").request().get()) {
+            assertEquals(400, response.getStatus());
+            assertNotEquals("{\"key\":\"key\",\"value\":\"value\"}", response.readEntity(String.class));
+        }
     }
 
     private static class TestJacksonJaxbJsonProvider extends JacksonJaxbJsonProvider {
diff --git a/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForEnabledModulesTest.java b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForEnabledModulesTest.java
index eaf293d..58a5e5a 100644
--- a/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForEnabledModulesTest.java
+++ b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/DefaultJsonJacksonProviderForEnabledModulesTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -22,7 +22,9 @@
 import org.junit.jupiter.api.Test;
 
 import jakarta.ws.rs.core.Application;
+import jakarta.ws.rs.core.Response;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotEquals;
 
 public class DefaultJsonJacksonProviderForEnabledModulesTest extends JerseyTest {
@@ -34,9 +36,10 @@
 
     @Test
     public final void testDisabledModule() {
-        final String response = target("entity/simple")
-                .request().get(String.class);
-        assertNotEquals("{\"name\":\"Hello\",\"value\":\"World\"}", response);
+        try (Response response = target("entity/simple").request().get()) {
+            assertEquals(400, response.getStatus());
+            assertNotEquals("{\"name\":\"Hello\",\"value\":\"World\"}", response.readEntity(String.class));
+        }
     }
 
 }
diff --git a/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/StreamReadConstrainsTest.java b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/StreamReadConstrainsTest.java
index 925c17e..8fa7cb9 100644
--- a/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/StreamReadConstrainsTest.java
+++ b/media/json-jackson/src/test/java/org/glassfish/jersey/jackson/internal/StreamReadConstrainsTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -50,6 +50,7 @@
 import java.util.List;
 
 public class StreamReadConstrainsTest extends JerseyTest {
+    private static final String ERROR_MSG_PART = "maximum allowed (";
 
     @Override
     protected final Application configure() {
@@ -78,7 +79,7 @@
                 .post(Entity.entity(new MyEntity(8), MediaType.APPLICATION_JSON_TYPE))) {
             Assertions.assertEquals(200, response.getStatus());
             String errorMsg = response.readEntity(String.class);
-            Assertions.assertTrue(errorMsg.contains("maximum length (4)"));
+            Assertions.assertTrue(errorMsg.contains(ERROR_MSG_PART + 4));
         }
     }
 
@@ -125,7 +126,7 @@
                 throw ex;
             }
             String errorMsg = ex.getCause().getMessage();
-            Assertions.assertTrue(errorMsg.contains("maximum length (" + String.valueOf(expectedLength) + ")"));
+            Assertions.assertTrue(errorMsg.contains(ERROR_MSG_PART + String.valueOf(expectedLength)));
         }
     }
 
@@ -137,7 +138,7 @@
                 + " Please update the code in " + DefaultJacksonJaxbJsonProvider.class.getName()
                 + " updateFactoryConstraints method";
         Method[] method = StreamReadConstraints.Builder.class.getDeclaredMethods();
-        Assertions.assertEquals(4, method.length, message); // three max + build methods
+        Assertions.assertEquals(6, method.length, message); // five setMax... + build() methods
     }
 
     @Path("len")
diff --git a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/ContentDisposition.java b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/ContentDisposition.java
index f95d521..6d77453 100644
--- a/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/ContentDisposition.java
+++ b/media/multipart/src/main/java/org/glassfish/jersey/media/multipart/ContentDisposition.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -28,8 +28,6 @@
 import org.glassfish.jersey.message.internal.HttpHeaderReader;
 import org.glassfish.jersey.uri.UriComponent;
 
-import jakarta.ws.rs.core.HttpHeaders;
-
 /**
  * A content disposition header.
  *
@@ -60,10 +58,13 @@
     private static final Pattern FILENAME_VALUE_CHARS_PATTERN =
             Pattern.compile("(%[a-f0-9]{2}|[a-z0-9!#$&+.^_`|~-])+", Pattern.CASE_INSENSITIVE);
 
+    private static final char QUOTE = '"';
+    private static final char BACK_SLASH = '\\';
+
     protected ContentDisposition(final String type, final String fileName, final Date creationDate,
                                  final Date modificationDate, final Date readDate, final long size) {
         this.type = type;
-        this.fileName = fileName;
+        this.fileName = encodeAsciiFileName(fileName);
         this.creationDate = creationDate;
         this.modificationDate = modificationDate;
         this.readDate = readDate;
@@ -211,6 +212,23 @@
         }
     }
 
+    protected String encodeAsciiFileName(String fileName) {
+        if (fileName == null
+                || (fileName.indexOf(QUOTE) == -1
+                && fileName.indexOf(BACK_SLASH) == -1)) {
+            return fileName;
+        }
+        final char[] chars = fileName.toCharArray();
+        final StringBuilder encodedBuffer = new StringBuilder();
+        for (char c : chars) {
+            if (c == QUOTE || c == BACK_SLASH) {
+                encodedBuffer.append(BACK_SLASH);
+            }
+            encodedBuffer.append(c);
+        }
+        return encodedBuffer.toString();
+    }
+
     private void createParameters() throws ParseException {
         defineFileName();
 
@@ -229,7 +247,7 @@
         final String fileNameExt = parameters.get("filename*");
 
         if (fileNameExt == null) {
-            this.fileName = fileName;
+            this.fileName = encodeAsciiFileName(fileName);
             return;
         }
 
diff --git a/pom.xml b/pom.xml
index 6ddfcde..d0641e2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2291,7 +2291,8 @@
         <hk2.jvnet.osgi.version>org.jvnet.hk2.*;version="[2.5,4)"</hk2.jvnet.osgi.version>
         <httpclient.version>4.5.14</httpclient.version>
         <httpclient5.version>5.2.1</httpclient5.version>
-        <jackson.version>2.15.3</jackson.version>
+        <jackson.version>2.16.1</jackson.version>
+        <jackson1.version>1.9.13</jackson1.version>
         <javassist.version>3.29.2-GA</javassist.version>
         <jboss.logging.version>3.5.3.Final</jboss.logging.version>
         <jboss.logging.8.version>3.4.3.Final</jboss.logging.8.version>
diff --git a/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/ContentDispositionTest.java b/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/ContentDispositionTest.java
index c4bcd53..8cecb6b 100644
--- a/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/ContentDispositionTest.java
+++ b/tests/e2e/src/test/java/org/glassfish/jersey/tests/api/ContentDispositionTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -89,6 +89,14 @@
     }
 
     @Test
+    void testContentDispositionEncoded() {
+        final Date date = new Date();
+        final ContentDisposition contentDisposition = ContentDisposition.type(contentDispositionType).fileName("\"rm\\ -rf\".sh")
+                .creationDate(date).modificationDate(date).readDate(date).size(312).build();
+        assertEquals("\\\"rm\\\\ -rf\\\".sh", contentDisposition.getFileName());
+    }
+
+    @Test
     public void testToString() {
         final Date date = new Date();
         final ContentDisposition contentDisposition = ContentDisposition.type(contentDispositionType).fileName("test.file")
diff --git a/tests/integration/property-check/pom.xml b/tests/integration/property-check/pom.xml
index df52904..ef3d8ac 100644
--- a/tests/integration/property-check/pom.xml
+++ b/tests/integration/property-check/pom.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
 
-    Copyright (c) 2014, 2023 Oracle and/or its affiliates. All rights reserved.
+    Copyright (c) 2014, 2024 Oracle and/or its affiliates. All rights reserved.
 
     This program and the accompanying materials are made available under the
     terms of the Eclipse Public License v. 2.0, which is available at
@@ -74,6 +74,11 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>org.glassfish.jersey.connectors</groupId>
+            <artifactId>jersey-apache5-connector</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.glassfish.jersey.security</groupId>
             <artifactId>oauth1-server</artifactId>
             <version>${project.version}</version>
@@ -109,28 +114,4 @@
             </plugin>
         </plugins>
     </build>
-
-    <profiles>
-        <profile>
-            <id>jdk19+</id>
-            <activation>
-                <jdk>[19,)</jdk>
-            </activation>
-            <build>
-                <pluginManagement>
-                    <plugins>
-                        <plugin>
-                            <groupId>org.apache.maven.plugins</groupId>
-                            <artifactId>maven-surefire-plugin</artifactId>
-                            <configuration>
-                                <excludes>
-                                    <exclude>**/SystemPropertiesConfigurationModelTest.java</exclude>
-                                </excludes>
-                            </configuration>
-                        </plugin>
-                    </plugins>
-                </pluginManagement>
-            </build>
-        </profile>
-    </profiles>
 </project>
diff --git a/tests/integration/property-check/src/test/java/org/glassfish/jersey/internal/config/SystemPropertiesConfigurationModelTest.java b/tests/integration/property-check/src/test/java/org/glassfish/jersey/internal/config/SystemPropertiesConfigurationModelTest.java
index ddb8e08..916bf81 100644
--- a/tests/integration/property-check/src/test/java/org/glassfish/jersey/internal/config/SystemPropertiesConfigurationModelTest.java
+++ b/tests/integration/property-check/src/test/java/org/glassfish/jersey/internal/config/SystemPropertiesConfigurationModelTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -32,6 +32,7 @@
 
 import org.glassfish.jersey.CommonProperties;
 import org.glassfish.jersey.apache.connector.ApacheClientProperties;
+import org.glassfish.jersey.apache5.connector.Apache5ClientProperties;
 import org.glassfish.jersey.client.ClientProperties;
 import org.glassfish.jersey.internal.InternalProperties;
 import org.glassfish.jersey.internal.util.JdkVersion;
@@ -79,8 +80,13 @@
     @Test
     public void propertyLoadedWhenSecurityException() {
         final String TEST_STRING = "test";
-        SecurityManager sm = System.getSecurityManager();
-        String policy = System.getProperty("java.security.policy");
+        final boolean isSm = JdkVersion.getJdkVersion().getMajor() < 19;
+        SecurityManager sm = null;
+        String policy = null;
+        if (isSm) {
+            sm = System.getSecurityManager();
+            policy = System.getProperty("java.security.policy");
+        }
         try {
             System.setProperty(CommonProperties.ALLOW_SYSTEM_PROPERTIES_PROVIDER, Boolean.TRUE.toString());
             System.setProperty(ServerProperties.APPLICATION_NAME, TEST_STRING);
@@ -88,15 +94,20 @@
             System.setProperty(ServletProperties.JAXRS_APPLICATION_CLASS, TEST_STRING);
             System.setProperty(MessageProperties.IO_BUFFER_SIZE, TEST_STRING);
             System.setProperty(ApacheClientProperties.DISABLE_COOKIES, TEST_STRING);
+            System.setProperty(Apache5ClientProperties.DISABLE_COOKIES, TEST_STRING);
             System.setProperty(JettyClientProperties.ENABLE_SSL_HOSTNAME_VERIFICATION, TEST_STRING);
             System.setProperty(MultiPartProperties.TEMP_DIRECTORY, TEST_STRING);
             System.setProperty(OAuth1ServerProperties.REALM, TEST_STRING);
             JerseySystemPropertiesConfigurationModel model = new JerseySystemPropertiesConfigurationModel();
             assertTrue(model.as(CommonProperties.ALLOW_SYSTEM_PROPERTIES_PROVIDER, Boolean.class));
-            String securityPolicy = SystemPropertiesConfigurationModelTest.class.getResource("/server.policy").getFile();
-            System.setProperty("java.security.policy", securityPolicy);
-            SecurityManager manager = new SecurityManager();
-            System.setSecurityManager(manager);
+
+            if (isSm) {
+                String securityPolicy = SystemPropertiesConfigurationModelTest.class.getResource("/server.policy").getFile();
+                System.setProperty("java.security.policy", securityPolicy);
+                SecurityManager manager = new SecurityManager();
+                System.setSecurityManager(manager);
+            }
+
             Map<String, Object> properties = model.getProperties();
             assertEquals(TEST_STRING, properties.get(ServerProperties.APPLICATION_NAME));
             assertEquals(Boolean.TRUE.toString(), properties.get(CommonProperties.ALLOW_SYSTEM_PROPERTIES_PROVIDER));
@@ -109,7 +120,9 @@
             assertEquals(TEST_STRING, properties.get(MessageProperties.IO_BUFFER_SIZE));
             assertFalse(properties.containsKey(MessageProperties.DEFLATE_WITHOUT_ZLIB));
             assertEquals(TEST_STRING, properties.get(ApacheClientProperties.DISABLE_COOKIES));
+            assertEquals(TEST_STRING, properties.get(Apache5ClientProperties.DISABLE_COOKIES));
             assertFalse(properties.containsKey(ApacheClientProperties.CONNECTION_MANAGER));
+            assertFalse(properties.containsKey(Apache5ClientProperties.CONNECTION_MANAGER));
             assertEquals(TEST_STRING, properties.get(JettyClientProperties.ENABLE_SSL_HOSTNAME_VERIFICATION));
             assertFalse(properties.containsKey(JettyClientProperties.DISABLE_COOKIES));
             assertEquals(TEST_STRING, properties.get(MultiPartProperties.TEMP_DIRECTORY));
@@ -120,7 +133,9 @@
             if (policy != null) {
                 System.setProperty("java.security.policy", policy);
             }
-            System.setSecurityManager(sm);
+            if (isSm) {
+                System.setSecurityManager(sm);
+            }
         }
     }