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>--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()); + } + +}