Skip to content

Commit

Permalink
Merge pull request #1550 from michalszynkiewicz/incoming-headers
Browse files Browse the repository at this point in the history
RestClient - passing incoming JAX-RS headers, fixes #1017
  • Loading branch information
kenfinnigan committed Mar 18, 2019
2 parents b2d51f2 + 4911a9c commit 0311eb8
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 5 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ recommended that you always run a full maven build before submitting a pull requ
#### Eclipse Setup

Open the *Preferences* window, and then navigate to _Java_ -> _Code Style_ -> _Formatter_. Click _Import_ and then
select the `eclipse-formatter.xml` file in the `ide-config` directory.
select the `eclipse-format.xml` file in the `ide-config` directory.

Next navigate to _Java_ -> _Code Style_ -> _Organize Imports_. Click _Import_ and select the `eclipse.importorder` file.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

import org.apache.commons.logging.impl.Jdk14Logger;
import org.apache.commons.logging.impl.LogFactoryImpl;
import org.eclipse.microprofile.rest.client.ext.DefaultClientHeadersFactoryImpl;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget;
Expand Down Expand Up @@ -176,10 +177,14 @@ void processInterfaces(CombinedIndexBuildItem combinedIndexBuildItem,

for (Map.Entry<DotName, ClassInfo> entry : interfaces.entrySet()) {
String iName = entry.getKey().toString();
// the SubstrateProxyDefinitions have to be separate because
// SmallRye creates a JDK proxy that delegates to a resteasy JDK proxy
proxyDefinition.produce(new SubstrateProxyDefinitionBuildItem(iName, ResteasyClientProxy.class.getName()));
proxyDefinition.produce(new SubstrateProxyDefinitionBuildItem(iName, RestClientProxy.class.getName()));
reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, iName));
}
// required for the non-arg constructor of DCHFImpl to be included in the native image
reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, DefaultClientHeadersFactoryImpl.class.getName()));

// Register Interface return types for reflection
for (Type returnType : returnTypes) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2019 Red Hat, Inc.
*
* Red Hat licenses this file to you under the Apache License, version
* 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package io.quarkus.smallrye.restclient.runtime;

import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;

import org.jboss.resteasy.specimpl.UnmodifiableMultivaluedMap;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.ResteasyProviderFactory;

/**
* @author Michal Szynkiewicz, michal.l.szynkiewicz@gmail.com
* <br>
* Date: 2/28/19
*/
public class IncomingHeadersProvider implements io.smallrye.restclient.header.IncomingHeadersProvider {
public static final UnmodifiableMultivaluedMap<String, String> EMPTY_MAP = new UnmodifiableMultivaluedMap<>(
new MultivaluedHashMap<>());

/**
* @return headers incoming in the JAX-RS request, if any
*/
@Override
public MultivaluedMap<String, String> getIncomingHeaders() {
MultivaluedMap<String, String> result = null;

ResteasyProviderFactory providerFactory = ResteasyProviderFactory.peekInstance();
if (providerFactory != null) {
HttpRequest request = (HttpRequest) providerFactory.getContextData(HttpRequest.class);
if (request != null) {
result = request.getHttpHeaders().getRequestHeaders();
}
}
return result == null
? EMPTY_MAP
: result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
io.quarkus.smallrye.restclient.runtime.IncomingHeadersProvider
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.net.URL;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;
import javax.ws.rs.GET;
Expand Down Expand Up @@ -45,7 +46,7 @@ public String manual() throws Exception {

@GET
@Path("/cdi")
public String cdi() throws Exception {
public String cdi() {
return restInterface.get();
}

Expand Down Expand Up @@ -85,4 +86,21 @@ public List<ComponentType> complexCdi() {
return restInterface.complex();
}

@GET
@Path("/manual/headers")
@Produces("application/json")
public Map<String, String> getAllHeaders(String headerValue) throws Exception {
ProgrammaticRestInterface client = RestClientBuilder.newBuilder()
.baseUrl(new URL(System.getProperty("test.url")))
.build(ProgrammaticRestInterface.class);
return client.getAllHeaders();
}

@GET
@Path("/cdi/headers")
@Produces("application/json")
public Map<String, String> getAllHeadersCdi(String headerValue) {
return restInterface.getAllHeaders();
}

}
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
package io.quarkus.example.rest;

import java.util.List;
import java.util.Map;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;

/**
* A version of {@link RestInterface} that doesn't have {@link org.eclipse.microprofile.rest.client.inject.RegisterRestClient}
* and can be used only programmatically, i.e. with the builder.
*/
@Path("/test")
@RegisterClientHeaders
public interface ProgrammaticRestInterface {

@GET
Expand All @@ -25,4 +29,9 @@ public interface ProgrammaticRestInterface {
@Path("/complex")
@Produces("application/json")
List<ComponentType> complex();

@GET
@Path("/headers")
@Produces("application/json")
Map<String, String> getAllHeaders();
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@
package io.quarkus.example.rest;

import java.util.List;
import java.util.Map;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

@RegisterRestClient
@Path("/test")
@RegisterClientHeaders
public interface RestInterface {

@GET
Expand All @@ -40,4 +43,9 @@ public interface RestInterface {
@Path("/complex")
@Produces("application/json")
List<ComponentType> complex();

@GET
@Path("/headers")
@Produces("application/json")
Map<String, String> getAllHeaders();
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
package io.quarkus.example.rest;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.atomic.AtomicInteger;
Expand All @@ -39,6 +41,7 @@
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.xml.bind.annotation.XmlRootElement;

Expand Down Expand Up @@ -147,6 +150,16 @@ public List<ComponentType> complex() {
return Collections.singletonList(ret);
}

@GET
@Path("/headers")
@Produces("application/json")
public Map<String, String> getAllHeaders(@Context HttpHeaders headers) {
Map<String, String> resultMap = new HashMap<>();
headers.getRequestHeaders().forEach(
(key, values) -> resultMap.put(key, String.join(",", values)));
return resultMap;
}

@GET
@Path("/subclass")
@Produces("application/json")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.eclipse.microprofile.rest.client.propagateHeaders=header-name
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@

package io.quarkus.example.test;

import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.*;

import java.util.List;
import java.util.Map;
Expand All @@ -26,14 +25,15 @@
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import io.quarkus.example.rest.ComponentType;
import io.quarkus.test.junit.QuarkusTest;
import io.restassured.RestAssured;
import io.restassured.path.json.JsonPath;

@QuarkusTest
public class RestClientTestCase {

public static final String HEADER_NAME = "header-name";

@Test
public void testMicroprofileClient() {
RestAssured.when().get("/client/manual").then()
Expand Down Expand Up @@ -78,6 +78,26 @@ void testMicroprofileClientComplexCdi() {
Assertions.assertEquals(map.get("value"), "component value");
}

@Test
void testMicroprofileCdiClientHeaderPassing() {
String headerValue = "some-not-at-all-random-header-value";
RestAssured
.given().header(HEADER_NAME, headerValue)
.when().get("/client/manual/headers")
.then().header("Content-Type", "application/json")
.body(HEADER_NAME, equalTo(headerValue));
}

@Test
void testMicroprofileClientHeaderPassing() {
String headerValue = "some-not-at-all-random-header-value";
RestAssured
.given().header(HEADER_NAME, headerValue)
.when().get("/client/cdi/headers")
.then().header("Content-Type", "application/json")
.body(HEADER_NAME, equalTo(headerValue));
}

/**
* Disabled by default as it establishes external connections.
* <p>
Expand Down

0 comments on commit 0311eb8

Please sign in to comment.