From 40bc889c3eca0bfecf6bc56585006b188dc16cdb Mon Sep 17 00:00:00 2001 From: jansupol Date: Fri, 10 Jan 2025 21:12:08 +0100 Subject: [PATCH] Support MP REST Client 4.0 Signed-off-by: jansupol --- .../microprofile/restclient/MethodModel.java | 7 +- .../restclient/RestClientBuilderImpl.java | 47 +++- .../restclient/RestClientProducer.java | 9 +- .../internal/localization.properties | 3 +- .../MultiPartHeaderModificationTest.java | 3 +- pom.xml | 6 +- tests/integration/microprofile/pom.xml | 1 + .../microprofile/rest-client-tck/pom.xml | 51 +++- .../microprofile/rest-client-tck3/pom.xml | 262 ++++++++++++++++++ .../src/test/resources/arquillian.xml | 29 ++ .../src/test/resources/server.policy | 19 ++ .../rest-client-tck3/tck-suite.xml | 29 ++ .../restclient/HttpHeaderTest.java | 131 +++++++++ 13 files changed, 576 insertions(+), 21 deletions(-) create mode 100644 tests/integration/microprofile/rest-client-tck3/pom.xml create mode 100644 tests/integration/microprofile/rest-client-tck3/src/test/resources/arquillian.xml create mode 100644 tests/integration/microprofile/rest-client-tck3/src/test/resources/server.policy create mode 100644 tests/integration/microprofile/rest-client-tck3/tck-suite.xml create mode 100644 tests/integration/microprofile/rest-client/src/test/java/org/glassfish/jersey/test/microprofile/restclient/HttpHeaderTest.java 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 9f8ebd1c6b..08eaf0a0ae 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 @@ private MultivaluedMap resolveCustomHeaders(Object[] args) { if (!headersContext.isPresent()) { for (InboundHeadersProvider provider : interfaceModel.context().inboundHeadersProviders()) { inbound.putAll(provider.inboundHeaders()); + if (RestClientBuilderImpl.DefaultInboundHeaderProvider.class.isInstance(provider)) { + MultivaluedMap 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 2b7425f6dc..687d228301 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 @@ class RestClientBuilderImpl implements RestClientBuilder { private final List asyncInterceptorFactories; private final Config config; private final ConfigWrapper configWrapper; + private final DefaultInboundHeaderProvider defaultInboundHeaderProvider; private URI uri; private ClientBuilder clientBuilder; private Supplier executorService; @@ -112,6 +119,9 @@ class RestClientBuilderImpl implements RestClientBuilder { 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 @@ public RestClientBuilder queryParamStyle(QueryParamStyle queryParamStyle) { 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 @@ Integer getPriority() { } } + /* package*/ static class DefaultInboundHeaderProvider implements InboundHeadersProvider, ClientHeadersFactory { + private final RuntimeDelegate delegate; + private final MultivaluedMap 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> inboundHeaders() { + return headers; + } + + @Override + public MultivaluedMap update(MultivaluedMap incomingHeaders, + MultivaluedMap clientOutgoingHeaders) { + MultivaluedMap 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 1fbf420802..0dff2b1108 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 @@ public Object create(CreationalContext creationalContext) { @Override public void destroy(Object instance, CreationalContext 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 3afc639ad8..5a3b07432a 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/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 e6ff2ed5db..73790c0f23 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 ecdaceeda9..d5a686117b 100644 --- a/pom.xml +++ b/pom.xml @@ -2150,7 +2150,8 @@ 3.0.3 - 3.0.1 + 3.0.1 + 4.0 3.2.6 3.2.8 1.4.14 @@ -2201,7 +2202,8 @@ 3.1.9.Final 8.0.1.Final - 2.27.2 + 2.27.2 + 3.10.0 2.12.2 diff --git a/tests/integration/microprofile/pom.xml b/tests/integration/microprofile/pom.xml index ded1778777..97a819fed1 100644 --- a/tests/integration/microprofile/pom.xml +++ b/tests/integration/microprofile/pom.xml @@ -34,6 +34,7 @@ config rest-client rest-client-tck + rest-client-tck3 diff --git a/tests/integration/microprofile/rest-client-tck/pom.xml b/tests/integration/microprofile/rest-client-tck/pom.xml index a370bbb49d..62c570eaa8 100644 --- a/tests/integration/microprofile/rest-client-tck/pom.xml +++ b/tests/integration/microprofile/rest-client-tck/pom.xml @@ -35,6 +35,24 @@ jersey-mp-rest-client ${project.version} test + + + org.eclipse.microprofile.rest.client + microprofile-rest-client-api + + + + + org.eclipse.microprofile.rest.client + microprofile-rest-client-api + ${microprofile.rest.client.version} + test + + + org.eclipse.microprofile.rest.client + microprofile-rest-client-tck + ${microprofile.rest.client.version} + test @@ -51,9 +69,8 @@ test - javax.servlet - javax.servlet-api - 4.0.1 + jakarta.servlet + jakarta.servlet-api io.smallrye.config @@ -61,22 +78,16 @@ ${smallrye.config.version} test - - org.eclipse.microprofile.rest.client - microprofile-rest-client-tck - ${microprofile.rest.client.version} - test - org.testng testng - ${testng6.version} + ${testng.version} test - com.github.tomakehurst + org.wiremock wiremock - ${wiremock.version} + ${wiremock.jetty11.version} test @@ -170,6 +181,11 @@ jersey-apache-connector test + + org.glassfish.jersey.media + jersey-media-multipart + test + org.glassfish.jersey.ext.cdi jersey-weld2-se @@ -239,11 +255,20 @@ + + securityOff + + [24,) + + + + + -Djava.security.manager -Djava.security.policy=${project.build.directory}/test-classes/server.policy - ${jetty9.version} + ${jetty11.version} 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 0000000000..c26ac727dd --- /dev/null +++ b/tests/integration/microprofile/rest-client-tck3/pom.xml @@ -0,0 +1,262 @@ + + + + + + microprofile-integration-project + org.glassfish.jersey.tests.integration.microprofile + 3.1.99-SNAPSHOT + + 4.0.0 + + jersey-rest-client-tck3 + + + + org.glassfish.jersey.ext.microprofile + jersey-mp-rest-client + ${project.version} + test + + + + jakarta.enterprise + jakarta.enterprise.cdi-api + + + jakarta.ejb + jakarta.ejb-api + + + org.jboss.weld.se + weld-se-core + test + + + javax.servlet + javax.servlet-api + 4.0.1 + + + io.smallrye.config + smallrye-config + ${smallrye.config.version} + test + + + org.eclipse.microprofile.rest.client + microprofile-rest-client-tck + ${microprofile.rest.client.version} + test + + + org.testng + testng + ${testng6.version} + test + + + com.github.tomakehurst + wiremock + ${wiremock.jetty9.version} + test + + + org.eclipse.jetty + jetty-server + + + org.eclipse.jetty + jetty-servlet + + + org.eclipse.jetty + jetty-servlets + + + org.eclipse.jetty + jetty-webapp + + + org.eclipse.jetty + jetty-proxy + + + + + com.google.guava + guava + ${guava.version} + + + org.eclipse.jetty + jetty-server + ${jetty.version} + test + + + org.eclipse.jetty + jetty-servlet + ${jetty.version} + test + + + org.eclipse.jetty + jetty-servlets + ${jetty.version} + test + + + org.eclipse.jetty + jetty-webapp + ${jetty.version} + test + + + org.eclipse.jetty + jetty-proxy + ${jetty.version} + test + + + org.jboss.arquillian.testng + arquillian-testng-container + ${arquillian.version} + test + + + org.jboss.arquillian.container + arquillian-container-test-spi + ${arquillian.version} + test + + + org.jboss.arquillian.container + arquillian-weld-embedded + ${arquillian.weld.version} + test + + + org.glassfish.jersey.test-framework + jersey-test-framework-core + test + + + org.glassfish.jersey.test-framework.providers + jersey-test-framework-provider-bundle + pom + test + + + org.glassfish.jersey.connectors + jersey-apache-connector + test + + + org.glassfish.jersey.ext.cdi + jersey-weld2-se + test + + + junit + junit + ${junit4.version} + + + + + + testRunner + + + + + + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + org.apache.maven.surefire + surefire-junit47 + ${surefire.mvn.plugin.version} + + + org.apache.maven.surefire + surefire-testng + ${surefire.mvn.plugin.version} + + + + 1 + + tck-suite.xml + + + + + + uk.co.deliverymind + wiremock-maven-plugin + ${wiremock.mvn.plugin.version} + + + test-compile + + run + + + target/classes + --port=8765 + + + + + + + + + + + securityOff + + [24,) + + + + + + + + + -Djava.security.manager -Djava.security.policy=${project.build.directory}/test-classes/server.policy + ${jetty9.version} + ${microprofile.rest.client3.version} + + + + 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 0000000000..fffd8c9207 --- /dev/null +++ b/tests/integration/microprofile/rest-client-tck3/src/test/resources/arquillian.xml @@ -0,0 +1,29 @@ + + + + + + + target/deployments + + 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 0000000000..d448842a4e --- /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 0000000000..c83fae3d4d --- /dev/null +++ b/tests/integration/microprofile/rest-client-tck3/tck-suite.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + 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 0000000000..fd31fe8d47 --- /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 clientHeaders = clientRequestContext.getHeaders(); + for (String headerName : clientHeaders.keySet()) { + List 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 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 headerParamHeaders = headerValues(headers, "HeaderParam"); + assertTrue(headerParamHeaders.contains("headerparam"), + "Header HeaderParam did not container \"headerparam\": " + headerParamHeaders); + } + + private static List 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()); + } + +}