Support MP REST Client 4.0 (#5831)

Signed-off-by: jansupol <jan.supol@oracle.com>

diff --git a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/MethodModel.java b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/MethodModel.java
index 9f8ebd1..08eaf0a 100644
--- a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/MethodModel.java
+++ b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/MethodModel.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, 2021 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2025 Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2019 Payara Foundation and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
@@ -379,6 +379,11 @@
         if (!headersContext.isPresent()) {
             for (InboundHeadersProvider provider : interfaceModel.context().inboundHeadersProviders()) {
                 inbound.putAll(provider.inboundHeaders());
+                if (RestClientBuilderImpl.DefaultInboundHeaderProvider.class.isInstance(provider)) {
+                    MultivaluedMap<String, String> fromFactory =
+                            ((ClientHeadersFactory) provider).update(inbound, customHeaders);
+                    customHeaders.putAll(fromFactory);
+                }
             }
         }
 
diff --git a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientBuilderImpl.java b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientBuilderImpl.java
index 2b7425f..687d228 100644
--- a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientBuilderImpl.java
+++ b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientBuilderImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, 2024 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2025 Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2019, 2021 Payara Foundation and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
@@ -47,8 +47,11 @@
 import jakarta.ws.rs.core.Configuration;
 import jakarta.ws.rs.core.Feature;
 import jakarta.ws.rs.core.FeatureContext;
+import jakarta.ws.rs.core.MultivaluedHashMap;
+import jakarta.ws.rs.core.MultivaluedMap;
 import jakarta.ws.rs.ext.ParamConverterProvider;
 
+import jakarta.ws.rs.ext.RuntimeDelegate;
 import org.eclipse.microprofile.config.Config;
 import org.eclipse.microprofile.config.ConfigProvider;
 import org.eclipse.microprofile.rest.client.RestClientBuilder;
@@ -56,6 +59,7 @@
 import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;
 import org.eclipse.microprofile.rest.client.ext.AsyncInvocationInterceptor;
 import org.eclipse.microprofile.rest.client.ext.AsyncInvocationInterceptorFactory;
+import org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory;
 import org.eclipse.microprofile.rest.client.ext.QueryParamStyle;
 import org.eclipse.microprofile.rest.client.ext.ResponseExceptionMapper;
 import org.eclipse.microprofile.rest.client.spi.RestClientListener;
@@ -66,10 +70,12 @@
 import org.glassfish.jersey.client.spi.ConnectorProvider;
 import org.glassfish.jersey.ext.cdi1x.internal.CdiUtil;
 import org.glassfish.jersey.innate.VirtualThreadUtil;
+import org.glassfish.jersey.internal.RuntimeDelegateDecorator;
 import org.glassfish.jersey.internal.ServiceFinder;
 import org.glassfish.jersey.internal.inject.InjectionManager;
 import org.glassfish.jersey.internal.inject.InjectionManagerSupplier;
 import org.glassfish.jersey.internal.util.ReflectionHelper;
+import org.glassfish.jersey.message.internal.HeaderUtils;
 import org.glassfish.jersey.uri.JerseyQueryParamStyle;
 
 /**
@@ -92,6 +98,7 @@
     private final List<AsyncInvocationInterceptorFactoryPriorityWrapper> asyncInterceptorFactories;
     private final Config config;
     private final ConfigWrapper configWrapper;
+    private final DefaultInboundHeaderProvider defaultInboundHeaderProvider;
     private URI uri;
     private ClientBuilder clientBuilder;
     private Supplier<ExecutorService> executorService;
@@ -112,6 +119,9 @@
         config = ConfigProvider.getConfig();
         configWrapper = new ConfigWrapper(clientBuilder.getConfiguration());
         executorService = () -> VirtualThreadUtil.withConfig(configWrapper).newCachedThreadPool();
+
+        defaultInboundHeaderProvider = new DefaultInboundHeaderProvider(clientBuilder.getConfiguration());
+        inboundHeaderProviders.add(defaultInboundHeaderProvider);
     }
 
     @Override
@@ -491,6 +501,11 @@
         return this;
     }
 
+    public RestClientBuilder header(String s, Object o) {
+        defaultInboundHeaderProvider.header(s, o);
+        return this;
+    }
+
     private static class InjectionManagerExposer implements Feature {
         InjectionManager injectionManager;
 
@@ -529,4 +544,34 @@
         }
     }
 
+    /* package*/ static class DefaultInboundHeaderProvider implements InboundHeadersProvider, ClientHeadersFactory {
+        private final RuntimeDelegate delegate;
+        private final MultivaluedMap<String, String> headers = new MultivaluedHashMap<>();
+
+        private DefaultInboundHeaderProvider(Configuration configuration) {
+            this.delegate = RuntimeDelegateDecorator.configured(configuration);
+        }
+
+        private void header(String key, Object value) {
+            if (value == null) {
+                throw new NullPointerException();
+            }
+            headers.add(key, HeaderUtils.asString(value, delegate));
+        }
+
+        @Override
+        public Map<String, List<String>> inboundHeaders() {
+            return headers;
+        }
+
+        @Override
+        public MultivaluedMap<String, String> update(MultivaluedMap<String, String> incomingHeaders,
+                                                     MultivaluedMap<String, String> clientOutgoingHeaders) {
+            MultivaluedMap<String, String> map = new MultivaluedHashMap<>();
+            map.putAll(incomingHeaders);
+            clientOutgoingHeaders.forEach((k, v) -> map.addAll(k, v));
+            return map;
+        }
+    }
+
 }
\ No newline at end of file
diff --git a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientProducer.java b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientProducer.java
index 1fbf420..0dff2b1 100644
--- a/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientProducer.java
+++ b/ext/microprofile/mp-rest-client/src/main/java/org/glassfish/jersey/microprofile/restclient/RestClientProducer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2025 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
@@ -161,6 +161,13 @@
 
     @Override
     public void destroy(Object instance, CreationalContext<Object> creationalContext) {
+        if (AutoCloseable.class.isInstance(instance)) {
+            try {
+                ((AutoCloseable) instance).close();
+            } catch (Exception e) {
+                throw new IllegalStateException(e);
+            }
+        }
     }
 
     @Override
diff --git a/ext/microprofile/mp-rest-client/src/main/resources/org/glassfish/jersey/microprofile/restclient/internal/localization.properties b/ext/microprofile/mp-rest-client/src/main/resources/org/glassfish/jersey/microprofile/restclient/internal/localization.properties
index 3afc639..5a3b074 100644
--- a/ext/microprofile/mp-rest-client/src/main/resources/org/glassfish/jersey/microprofile/restclient/internal/localization.properties
+++ b/ext/microprofile/mp-rest-client/src/main/resources/org/glassfish/jersey/microprofile/restclient/internal/localization.properties
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2021, 2025 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,3 +16,4 @@
 
 err.invalid.proxy.uri=Invalid proxy URI: {0}.
 err.invalid.proxy.port=Invalid proxy port: {0}.
+err.null.header=Header cannot be null.
diff --git a/media/multipart/pom.xml b/media/multipart/pom.xml
index d1d97a8..46a1ca2 100644
--- a/media/multipart/pom.xml
+++ b/media/multipart/pom.xml
@@ -98,7 +98,6 @@
             <version>${project.version}</version>
             <scope>test</scope>
         </dependency>
-
         <dependency>
             <groupId>org.junit.jupiter</groupId>
             <artifactId>junit-jupiter</artifactId>
diff --git a/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/MultiPartHeaderModificationTest.java b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/MultiPartHeaderModificationTest.java
index e6ff2ed..73790c0 100644
--- a/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/MultiPartHeaderModificationTest.java
+++ b/media/multipart/src/test/java/org/glassfish/jersey/media/multipart/internal/MultiPartHeaderModificationTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2025 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -36,7 +36,6 @@
 import org.glassfish.jersey.client.HttpUrlConnectorProvider;
 import org.glassfish.jersey.client.spi.ConnectorProvider;
 import org.glassfish.jersey.grizzly.connector.GrizzlyConnectorProvider;
-import org.glassfish.jersey.jetty.connector.JettyConnectorProvider;
 import org.glassfish.jersey.media.multipart.MultiPart;
 import org.glassfish.jersey.test.TestProperties;
 import org.glassfish.jersey.test.spi.TestHelper;
diff --git a/pom.xml b/pom.xml
index ecdacee..d5a6861 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2150,7 +2150,8 @@
 
         <!-- microprofile -->
         <microprofile.config.version>3.0.3</microprofile.config.version>
-        <microprofile.rest.client.version>3.0.1</microprofile.rest.client.version>
+        <microprofile.rest.client3.version>3.0.1</microprofile.rest.client3.version>
+        <microprofile.rest.client.version>4.0</microprofile.rest.client.version>
         <helidon.config.version>3.2.6</helidon.config.version>
         <helidon.connector.version>3.2.8</helidon.connector.version>
         <helidon.config.11.version>1.4.14</helidon.config.11.version> <!-- JDK 11- support -->
@@ -2201,7 +2202,8 @@
         <weld3.version>3.1.9.Final</weld3.version>
         <validation.impl.version>8.0.1.Final</validation.impl.version>
         <!-- END of Jakartified, eligible for CQ -->
-        <wiremock.version>2.27.2</wiremock.version>
+        <wiremock.jetty9.version>2.27.2</wiremock.jetty9.version>
+        <wiremock.jetty11.version>3.10.0</wiremock.jetty11.version>
         <xerces.version>2.12.2</xerces.version>
 
         <!-- Graal VM       -->
diff --git a/tests/integration/microprofile/pom.xml b/tests/integration/microprofile/pom.xml
index ded1778..97a819f 100644
--- a/tests/integration/microprofile/pom.xml
+++ b/tests/integration/microprofile/pom.xml
@@ -34,6 +34,7 @@
         <module>config</module>
         <module>rest-client</module>
         <module>rest-client-tck</module>
+        <module>rest-client-tck3</module>
     </modules>
 
     <build>
diff --git a/tests/integration/microprofile/rest-client-tck/pom.xml b/tests/integration/microprofile/rest-client-tck/pom.xml
index a370bbb..62c570e 100644
--- a/tests/integration/microprofile/rest-client-tck/pom.xml
+++ b/tests/integration/microprofile/rest-client-tck/pom.xml
@@ -35,6 +35,24 @@
             <artifactId>jersey-mp-rest-client</artifactId>
             <version>${project.version}</version>
             <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.eclipse.microprofile.rest.client</groupId>
+                    <artifactId>microprofile-rest-client-api</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.microprofile.rest.client</groupId>
+            <artifactId>microprofile-rest-client-api</artifactId>
+            <version>${microprofile.rest.client.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.microprofile.rest.client</groupId>
+            <artifactId>microprofile-rest-client-tck</artifactId>
+            <version>${microprofile.rest.client.version}</version>
+            <scope>test</scope>
         </dependency>
         <!-- Overrides CDI from parent pom -->
         <dependency>
@@ -51,9 +69,8 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>javax.servlet</groupId>
-            <artifactId>javax.servlet-api</artifactId>
-            <version>4.0.1</version>
+            <groupId>jakarta.servlet</groupId>
+            <artifactId>jakarta.servlet-api</artifactId>
         </dependency>
         <dependency>
             <groupId>io.smallrye.config</groupId>
@@ -62,21 +79,15 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.eclipse.microprofile.rest.client</groupId>
-            <artifactId>microprofile-rest-client-tck</artifactId>
-            <version>${microprofile.rest.client.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
             <groupId>org.testng</groupId>
             <artifactId>testng</artifactId>
-            <version>${testng6.version}</version>
+            <version>${testng.version}</version>
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>com.github.tomakehurst</groupId>
+            <groupId>org.wiremock</groupId>
             <artifactId>wiremock</artifactId>
-            <version>${wiremock.version}</version>
+            <version>${wiremock.jetty11.version}</version>
             <scope>test</scope>
             <exclusions>
                 <exclusion>
@@ -171,6 +182,11 @@
             <scope>test</scope>
         </dependency>
         <dependency>
+            <groupId>org.glassfish.jersey.media</groupId>
+            <artifactId>jersey-media-multipart</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.glassfish.jersey.ext.cdi</groupId>
             <artifactId>jersey-weld2-se</artifactId>
             <scope>test</scope>
@@ -239,11 +255,20 @@
                 </plugins>
             </build>
         </profile>
+        <profile>
+            <id>securityOff</id>
+            <activation>
+                <jdk>[24,)</jdk>
+            </activation>
+            <properties>
+                <surefire.security.argline />
+            </properties>
+        </profile>
     </profiles>
 
     <properties>
         <surefire.security.argline>-Djava.security.manager -Djava.security.policy=${project.build.directory}/test-classes/server.policy</surefire.security.argline>
-        <jetty.version>${jetty9.version}</jetty.version>
+        <jetty.version>${jetty11.version}</jetty.version>
     </properties>
 
 
diff --git a/tests/integration/microprofile/rest-client-tck3/pom.xml b/tests/integration/microprofile/rest-client-tck3/pom.xml
new file mode 100644
index 0000000..c26ac72
--- /dev/null
+++ b/tests/integration/microprofile/rest-client-tck3/pom.xml
@@ -0,0 +1,262 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2019, 2025 Oracle and/or its affiliates. All rights reserved.
+
+    This program and the accompanying materials are made available under the
+    terms of the Eclipse Public License v. 2.0, which is available at
+    http://www.eclipse.org/legal/epl-2.0.
+
+    This Source Code may also be made available under the following Secondary
+    Licenses when the conditions for such availability set forth in the
+    Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+    version 2 with the GNU Classpath Exception, which is available at
+    https://www.gnu.org/software/classpath/license.html.
+
+    SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>microprofile-integration-project</artifactId>
+        <groupId>org.glassfish.jersey.tests.integration.microprofile</groupId>
+        <version>3.1.99-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>jersey-rest-client-tck3</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext.microprofile</groupId>
+            <artifactId>jersey-mp-rest-client</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <!-- Overrides CDI from parent pom -->
+        <dependency>
+            <groupId>jakarta.enterprise</groupId>
+            <artifactId>jakarta.enterprise.cdi-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>jakarta.ejb</groupId>
+            <artifactId>jakarta.ejb-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.weld.se</groupId>
+            <artifactId>weld-se-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <version>4.0.1</version>
+        </dependency>
+        <dependency>
+            <groupId>io.smallrye.config</groupId>
+            <artifactId>smallrye-config</artifactId>
+            <version>${smallrye.config.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.microprofile.rest.client</groupId>
+            <artifactId>microprofile-rest-client-tck</artifactId>
+            <version>${microprofile.rest.client.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.testng</groupId>
+            <artifactId>testng</artifactId>
+            <version>${testng6.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.github.tomakehurst</groupId>
+            <artifactId>wiremock</artifactId>
+            <version>${wiremock.jetty9.version}</version>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.eclipse.jetty</groupId>
+                    <artifactId>jetty-server</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.eclipse.jetty</groupId>
+                    <artifactId>jetty-servlet</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.eclipse.jetty</groupId>
+                    <artifactId>jetty-servlets</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.eclipse.jetty</groupId>
+                    <artifactId>jetty-webapp</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.eclipse.jetty</groupId>
+                    <artifactId>jetty-proxy</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>${guava.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-server</artifactId>
+            <version>${jetty.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-servlet</artifactId>
+            <version>${jetty.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-servlets</artifactId>
+            <version>${jetty.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-webapp</artifactId>
+            <version>${jetty.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-proxy</artifactId>
+            <version>${jetty.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.arquillian.testng</groupId>
+            <artifactId>arquillian-testng-container</artifactId>
+            <version>${arquillian.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.arquillian.container</groupId>
+            <artifactId>arquillian-container-test-spi</artifactId>
+            <version>${arquillian.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.arquillian.container</groupId>
+            <artifactId>arquillian-weld-embedded</artifactId>
+            <version>${arquillian.weld.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework</groupId>
+            <artifactId>jersey-test-framework-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+            <artifactId>jersey-test-framework-provider-bundle</artifactId>
+            <type>pom</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.connectors</groupId>
+            <artifactId>jersey-apache-connector</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.ext.cdi</groupId>
+            <artifactId>jersey-weld2-se</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>${junit4.version}</version>
+        </dependency>
+    </dependencies>
+
+    <profiles>
+        <profile>
+            <id>testRunner</id>
+<!-- DO NOT ACTIVATE BY DEFAULT, tests are run by rest-client-tck (4) -->
+<!-- Kept for case of an error found in version 3 -->
+<!--            <activation>-->
+<!--                <property>-->
+<!--                    <name>skipTests</name>-->
+<!--                    <value>!true</value>-->
+<!--                </property>-->
+<!--                <jdk>[17,)</jdk>-->
+<!--            </activation>-->
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <dependencies>
+                            <dependency>
+                                <groupId>org.apache.maven.surefire</groupId>
+                                <artifactId>surefire-junit47</artifactId>
+                                <version>${surefire.mvn.plugin.version}</version>
+                            </dependency>
+                            <dependency>
+                                <groupId>org.apache.maven.surefire</groupId>
+                                <artifactId>surefire-testng</artifactId>
+                                <version>${surefire.mvn.plugin.version}</version>
+                            </dependency>
+                        </dependencies>
+                        <configuration>
+                            <threadCount>1</threadCount>
+                            <suiteXmlFiles>
+                                <suiteXmlFile>tck-suite.xml</suiteXmlFile>
+                            </suiteXmlFiles>
+<!--                            <argLine>-verbose:class</argLine>-->
+                        </configuration>
+                    </plugin>
+                    <plugin>
+                        <groupId>uk.co.deliverymind</groupId>
+                        <artifactId>wiremock-maven-plugin</artifactId>
+                        <version>${wiremock.mvn.plugin.version}</version>
+                        <executions>
+                            <execution>
+                                <phase>test-compile</phase>
+                                <goals>
+                                    <goal>run</goal>
+                                </goals>
+                                <configuration>
+                                    <dir>target/classes</dir>
+                                    <params>--port=8765</params>
+                                    <!-- Enable verbose for more detailed output-->
+                                    <!-- <params>&#45;&#45;verbose</params>-->
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>securityOff</id>
+            <activation>
+                <jdk>[24,)</jdk>
+            </activation>
+            <properties>
+                <surefire.security.argline />
+            </properties>
+        </profile>
+    </profiles>
+
+    <properties>
+        <surefire.security.argline>-Djava.security.manager -Djava.security.policy=${project.build.directory}/test-classes/server.policy</surefire.security.argline>
+        <jetty.version>${jetty9.version}</jetty.version>
+        <microprofile.rest.client.version>${microprofile.rest.client3.version}</microprofile.rest.client.version>
+    </properties>
+
+
+</project>
diff --git a/tests/integration/microprofile/rest-client-tck3/src/test/resources/arquillian.xml b/tests/integration/microprofile/rest-client-tck3/src/test/resources/arquillian.xml
new file mode 100644
index 0000000..fffd8c9
--- /dev/null
+++ b/tests/integration/microprofile/rest-client-tck3/src/test/resources/arquillian.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Copyright (c) 2019, 2025 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
+
+-->
+
+<arquillian xmlns="http://jboss.org/schema/arquillian"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="
+        http://jboss.org/schema/arquillian
+        http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
+
+    <engine>
+        <property name="deploymentExportPath">target/deployments</property>
+    </engine>
+</arquillian>
diff --git a/tests/integration/microprofile/rest-client-tck3/src/test/resources/server.policy b/tests/integration/microprofile/rest-client-tck3/src/test/resources/server.policy
new file mode 100644
index 0000000..d448842
--- /dev/null
+++ b/tests/integration/microprofile/rest-client-tck3/src/test/resources/server.policy
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2019, 2025 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
+ */
+
+grant {
+  permission java.security.AllPermission;
+};
diff --git a/tests/integration/microprofile/rest-client-tck3/tck-suite.xml b/tests/integration/microprofile/rest-client-tck3/tck-suite.xml
new file mode 100644
index 0000000..c83fae3
--- /dev/null
+++ b/tests/integration/microprofile/rest-client-tck3/tck-suite.xml
@@ -0,0 +1,29 @@
+<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
+<!--
+
+    Copyright (c) 2019, 2025 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
+
+-->
+
+<suite name="microprofile-rest-client-TCK" verbose="2" configfailurepolicy="continue">
+
+    <test name="microprofile-rest-client TCK">
+        <packages>
+            <package name="org.eclipse.microprofile.rest.client.tck.*">
+            </package>
+        </packages>
+    </test>
+
+</suite>
diff --git a/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/HttpHeaderTest.java b/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/HttpHeaderTest.java
new file mode 100644
index 0000000..fd31fe8
--- /dev/null
+++ b/tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/HttpHeaderTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package org.glassfish.jersey.test.microprofile.restclient;
+
+import jakarta.json.Json;
+import jakarta.json.JsonArray;
+import jakarta.json.JsonArrayBuilder;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonObjectBuilder;
+import jakarta.json.JsonString;
+import jakarta.json.JsonValue;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.HeaderParam;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.client.ClientRequestContext;
+import jakarta.ws.rs.client.ClientRequestFilter;
+import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.core.Response;
+import org.eclipse.microprofile.rest.client.RestClientBuilder;
+import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class HttpHeaderTest {
+    @Path("/")
+    public interface HeaderResource {
+        @GET
+        public String get();
+    }
+
+    @Test
+    public void restclientBuilderWithHeadersTest() {
+        String headerName = "BUILDER_HEADER";
+        String headerValue = "BUILDER_VALUE";
+        HeaderResource resource = RestClientBuilder.newBuilder()
+                .baseUri("http://localhost:8080")
+                .register(new ClientRequestFilter() {
+                    @Override
+                    public void filter(ClientRequestContext requestContext) throws IOException {
+                        if (requestContext.getHeaders().containsKey(headerName)) {
+                            requestContext.abortWith(Response.ok(requestContext.getHeaders().getFirst(headerName)).build());
+                        } else {
+                            requestContext.abortWith(Response.ok("no_header").build());
+                        }
+                    }
+                })
+                .header(headerName, headerValue)
+                .build(HeaderResource.class);
+        Assertions.assertEquals(headerValue, resource.get());
+    }
+
+    @ClientHeaderParam(name = "InterfaceAndBuilderHeader", value = "interface")
+    @Path("/")
+    public interface ClientBuilderHeaderClient {
+
+        @GET
+        JsonObject getAllHeaders(@HeaderParam("HeaderParam") String param);
+    }
+
+    public static class ReturnWithAllDuplicateClientHeadersFilter implements ClientRequestFilter {
+
+        @Override
+        public void filter(ClientRequestContext clientRequestContext) throws IOException {
+            JsonObjectBuilder allClientHeaders = Json.createObjectBuilder();
+            MultivaluedMap<String, Object> clientHeaders = clientRequestContext.getHeaders();
+            for (String headerName : clientHeaders.keySet()) {
+                List<Object> header = clientHeaders.get(headerName);
+                final JsonArrayBuilder headerValues = Json.createArrayBuilder();
+                header.forEach(h -> headerValues.add(h.toString()));
+                allClientHeaders.add(headerName, headerValues);
+            }
+            clientRequestContext.abortWith(Response.ok(allClientHeaders.build()).build());
+        }
+
+    }
+
+    @Test
+    public void testHeaderBuilderInterface() {
+
+        RestClientBuilder builder = RestClientBuilder.newBuilder().baseUri("http://localhost:8080/");
+        builder.register(ReturnWithAllDuplicateClientHeadersFilter.class);
+        builder.header("InterfaceAndBuilderHeader", "builder");
+        ClientBuilderHeaderClient client = builder.build(ClientBuilderHeaderClient.class);
+
+        checkHeaders(client.getAllHeaders("headerparam"), "interface");
+    }
+
+    private static void checkHeaders(final JsonObject headers, final String clientHeaderParamName) {
+        final List<String> clientRequestHeaders = headerValues(headers, "InterfaceAndBuilderHeader");
+
+        assertTrue(clientRequestHeaders.contains("builder"),
+                "Header InterfaceAndBuilderHeader did not container \"builder\": " + clientRequestHeaders);
+        assertTrue(clientRequestHeaders.contains(clientHeaderParamName),
+                "Header InterfaceAndBuilderHeader did not container \"" + clientHeaderParamName + "\": "
+                        + clientRequestHeaders);
+
+        final List<String> headerParamHeaders = headerValues(headers, "HeaderParam");
+        assertTrue(headerParamHeaders.contains("headerparam"),
+                "Header HeaderParam did not container \"headerparam\": " + headerParamHeaders);
+    }
+
+    private static List<String> headerValues(final JsonObject headers, final String headerName) {
+        final JsonArray headerValues = headers.getJsonArray(headerName);
+        Assertions.assertNotNull(headerValues,
+                String.format("Expected header '%s' to be present in %s", headerName, headers));
+        return headerValues.stream().map(
+                        v -> (v.getValueType() == JsonValue.ValueType.STRING ? ((JsonString) v).getString() : v.toString()))
+                .collect(Collectors.toList());
+    }
+
+}