Browse Source

Create client using javax.ws.rs.client.Client (#696)

9.x
Marvin Froeder 6 years ago committed by GitHub
parent
commit
cfa0d07b65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 23
      jaxrs2/pom.xml
  2. 134
      jaxrs2/src/main/java/feign/jaxrs2/JAXRSClient.java
  3. 122
      jaxrs2/src/test/java/feign/jaxrs2/JAXRSClientTest.java

23
jaxrs2/pom.xml

@ -78,5 +78,28 @@ @@ -78,5 +78,28 @@
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.26</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>2.26</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>mockwebserver</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>java-hamcrest</artifactId>
<version>2.0.0.0</version>
</dependency>
</dependencies>
</project>

134
jaxrs2/src/main/java/feign/jaxrs2/JAXRSClient.java

@ -0,0 +1,134 @@ @@ -0,0 +1,134 @@
/**
* Copyright 2012-2018 The Feign Authors
*
* Licensed 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 feign.jaxrs2;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.*;
import feign.Client;
import feign.Request.Options;
/**
* This module directs Feign's http requests to javax.ws.rs.client.Client . Ex:
*
* <pre>
* GitHub github =
* Feign.builder().client(new JaxRSClient()).target(GitHub.class, "https://api.github.com");
* </pre>
*/
public class JAXRSClient implements Client {
private final ClientBuilder clientBuilder;
public JAXRSClient() {
this(ClientBuilder.newBuilder());
}
public JAXRSClient(ClientBuilder clientBuilder) {
this.clientBuilder = clientBuilder;
}
@Override
public feign.Response execute(feign.Request request, Options options) throws IOException {
final Response response = clientBuilder
.connectTimeout(options.connectTimeoutMillis(), TimeUnit.MILLISECONDS)
.readTimeout(options.readTimeoutMillis(), TimeUnit.MILLISECONDS)
.build()
.target(request.url())
.request()
.headers(toMultivaluedMap(request.headers()))
.method(request.method(), createRequestEntity(request));
return feign.Response.builder()
.request(request)
.body(response.readEntity(InputStream.class),
integerHeader(response, HttpHeaders.CONTENT_LENGTH))
.headers(toMap(response.getStringHeaders()))
.status(response.getStatus())
.reason(response.getStatusInfo().getReasonPhrase())
.build();
}
private Entity<byte[]> createRequestEntity(feign.Request request) {
if (request.body() == null) {
return null;
}
return Entity.entity(
request.body(),
new Variant(mediaType(request.headers()), locale(request.headers()),
encoding(request.charset())));
}
private Integer integerHeader(Response response, String header) {
final MultivaluedMap<String, String> headers = response.getStringHeaders();
if (!headers.containsKey(header)) {
return null;
}
try {
return new Integer(headers.getFirst(header));
} catch (final NumberFormatException e) {
// not a number or too big to fit Integer
return null;
}
}
private String encoding(Charset charset) {
if (charset == null)
return null;
return charset.name();
}
private String locale(Map<String, Collection<String>> headers) {
if (!headers.containsKey(HttpHeaders.CONTENT_LANGUAGE))
return null;
return headers.get(HttpHeaders.CONTENT_LANGUAGE).iterator().next();
}
private MediaType mediaType(Map<String, Collection<String>> headers) {
if (!headers.containsKey(HttpHeaders.CONTENT_TYPE))
return null;
return MediaType.valueOf(headers.get(HttpHeaders.CONTENT_TYPE).iterator().next());
}
private MultivaluedMap<String, Object> toMultivaluedMap(Map<String, Collection<String>> headers) {
final MultivaluedHashMap<String, Object> mvHeaders = new MultivaluedHashMap<>();
headers.entrySet().forEach(entry -> entry.getValue().stream()
.forEach(value -> mvHeaders.add(entry.getKey(), value)));
return mvHeaders;
}
private Map<String, Collection<String>> toMap(MultivaluedMap<String, String> headers) {
return headers.entrySet().stream()
.collect(Collectors.toMap(
Entry::getKey,
Entry::getValue));
}
}

122
jaxrs2/src/test/java/feign/jaxrs2/JAXRSClientTest.java

@ -0,0 +1,122 @@ @@ -0,0 +1,122 @@
/**
* Copyright 2012-2018 The Feign Authors
*
* Licensed 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 feign.jaxrs2;
import feign.Feign.Builder;
import feign.Headers;
import feign.RequestLine;
import feign.Response;
import feign.Util;
import feign.assertj.MockWebServerAssertions;
import feign.client.AbstractClientTest;
import feign.jaxrs2.JAXRSClient;
import feign.Feign;
import okhttp3.mockwebserver.MockResponse;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import javax.ws.rs.ProcessingException;
import static feign.Util.UTF_8;
import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import org.junit.Assume;
/** Tests client-specific behavior, such as ensuring Content-Length is sent when specified. */
public class JAXRSClientTest extends AbstractClientTest {
@Override
public Builder newBuilder() {
return Feign.builder().client(new JAXRSClient());
}
@Override
public void testPatch() throws Exception {
try {
super.testPatch();
} catch (final ProcessingException e) {
Assume.assumeNoException("JaxRS client do not support PATCH requests", e);
}
}
@Override
public void noResponseBodyForPut() {
try {
super.noResponseBodyForPut();
} catch (final IllegalStateException e) {
Assume.assumeNoException("JaxRS client do not support empty bodies on PUT", e);
}
}
@Test
public void reasonPhraseIsOptional() throws IOException, InterruptedException {
server.enqueue(new MockResponse().setStatus("HTTP/1.1 " + 200));
final TestInterface api = newBuilder()
.target(TestInterface.class, "http://localhost:" + server.getPort());
final Response response = api.post("foo");
assertThat(response.status()).isEqualTo(200);
// jaxrsclient is creating a reason when none is present
// assertThat(response.reason()).isNullOrEmpty();
}
@Test
public void parsesRequestAndResponse() throws IOException, InterruptedException {
server.enqueue(new MockResponse().setBody("foo").addHeader("Foo: Bar"));
final TestInterface api = newBuilder()
.target(TestInterface.class, "http://localhost:" + server.getPort());
final Response response = api.post("foo");
assertThat(response.status()).isEqualTo(200);
assertThat(response.reason()).isEqualTo("OK");
assertThat(response.headers())
.containsEntry("Content-Length", asList("3"))
.containsEntry("Foo", asList("Bar"));
assertThat(response.body().asInputStream())
.hasContentEqualTo(new ByteArrayInputStream("foo".getBytes(UTF_8)));
MockWebServerAssertions.assertThat(server.takeRequest()).hasMethod("POST")
.hasPath("/?foo=bar&foo=baz&qux=")
.hasBody("foo");
}
@Test
public void testContentTypeWithoutCharset2() throws Exception {
server.enqueue(new MockResponse()
.setBody("AAAAAAAA"));
final JaxRSClientTestInterface api = newBuilder()
.target(JaxRSClientTestInterface.class, "http://localhost:" + server.getPort());
final Response response = api.getWithContentType();
// Response length should not be null
assertEquals("AAAAAAAA", Util.toString(response.body().asReader()));
MockWebServerAssertions.assertThat(server.takeRequest())
.hasHeaders("Accept: text/plain", "Content-Type: text/plain") // Note: OkHttp adds content
// length.
.hasMethod("GET");
}
public interface JaxRSClientTestInterface {
@RequestLine("GET /")
@Headers({"Accept: text/plain", "Content-Type: text/plain"})
Response getWithContentType();
}
}
Loading…
Cancel
Save