-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduced java 11 module with http2 client (#806)
* Introduced java 11 module with http2 client
- Loading branch information
Showing
6 changed files
with
333 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# feign-java11 | ||
|
||
This module directs Feign's http requests to Java11 [New HTTP/2 Client](http://www.javamagazine.mozaicreader.com/JulyAug2017#&pageSet=39&page=0) that implements HTTP/2. | ||
|
||
To use New HTTP/2 Client with Feign, use Java SDK 11. Then, configure Feign to use the Http2Client: | ||
|
||
```java | ||
GitHub github = Feign.builder() | ||
.client(new Http2Client()) | ||
.target(GitHub.class, "https://api.github.com"); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!-- | ||
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. | ||
--> | ||
<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> | ||
<groupId>io.github.openfeign</groupId> | ||
<artifactId>parent</artifactId> | ||
<version>10.0.2-SNAPSHOT</version> | ||
</parent> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<artifactId>feign-java11</artifactId> | ||
<name>Feign Java 11</name> | ||
<description>Feign Java 11</description> | ||
|
||
<properties> | ||
<!-- override default bytecode version for src/main from parent pom --> | ||
<main.java.version>11</main.java.version> | ||
<main.signature.artifact>java18</main.signature.artifact> | ||
<main.basedir>${project.basedir}/..</main.basedir> | ||
<maven.compiler.source>11</maven.compiler.source> | ||
<maven.compiler.target>11</maven.compiler.target> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>${project.groupId}</groupId> | ||
<artifactId>feign-core</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>${project.groupId}</groupId> | ||
<artifactId>feign-jackson</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.squareup.okhttp3</groupId> | ||
<artifactId>mockwebserver</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>org.assertj</groupId> | ||
<artifactId>assertj-core</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>junit</groupId> | ||
<artifactId>junit</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>io.github.openfeign</groupId> | ||
<artifactId>feign-core</artifactId> | ||
<version>${project.version}</version> | ||
<classifier>tests</classifier> | ||
<type>jar</type> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.codehaus.mojo</groupId> | ||
<artifactId>animal-sniffer-maven-plugin</artifactId> | ||
<configuration> | ||
<!-- skipping execution, as plugin is not able to handle java 11 --> | ||
<skip>true</skip> | ||
</configuration> | ||
</plugin> | ||
|
||
</plugins> | ||
</build> | ||
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
/** | ||
* 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.httpclient; | ||
|
||
import java.io.ByteArrayInputStream; | ||
import java.io.IOException; | ||
import java.net.URI; | ||
import java.net.URISyntaxException; | ||
import java.net.http.HttpClient; | ||
import java.net.http.HttpClient.Redirect; | ||
import java.net.http.HttpRequest; | ||
import java.net.http.HttpRequest.BodyPublisher; | ||
import java.net.http.HttpRequest.BodyPublishers; | ||
import java.net.http.HttpResponse; | ||
import java.net.http.HttpResponse.BodyHandlers; | ||
import java.util.*; | ||
import java.util.function.Function; | ||
import java.util.stream.Collectors; | ||
import feign.Client; | ||
import feign.Request; | ||
import feign.Request.Options; | ||
import feign.Response; | ||
|
||
public class Http2Client implements Client { | ||
|
||
@Override | ||
public Response execute(Request request, Options options) throws IOException { | ||
final HttpClient client = HttpClient.newBuilder() | ||
.followRedirects(Redirect.ALWAYS) | ||
.build(); | ||
|
||
URI uri; | ||
try { | ||
uri = new URI(request.url()); | ||
} catch (final URISyntaxException e) { | ||
throw new IOException("Invalid uri " + request.url(), e); | ||
} | ||
|
||
final BodyPublisher body; | ||
if (request.body() == null) { | ||
body = BodyPublishers.noBody(); | ||
} else { | ||
body = BodyPublishers.ofByteArray(request.body()); | ||
} | ||
|
||
final HttpRequest httpRequest = HttpRequest.newBuilder() | ||
.uri(uri) | ||
.method(request.method(), body) | ||
.headers(asString(filterRestrictedHeaders(request.headers()))) | ||
.build(); | ||
|
||
HttpResponse<byte[]> httpResponse; | ||
try { | ||
httpResponse = client.send(httpRequest, BodyHandlers.ofByteArray()); | ||
} catch (final InterruptedException e) { | ||
throw new IOException("Invalid uri " + request.url(), e); | ||
} | ||
|
||
System.out.println(httpResponse.headers().map()); | ||
|
||
final OptionalLong length = httpResponse.headers().firstValueAsLong("Content-Length"); | ||
|
||
final Response response = Response.builder() | ||
.body(new ByteArrayInputStream(httpResponse.body()), | ||
length.isPresent() ? (int) length.getAsLong() : null) | ||
.reason(httpResponse.headers().firstValue("Reason-Phrase").orElse(null)) | ||
.request(request) | ||
.status(httpResponse.statusCode()) | ||
.headers(castMapCollectType(httpResponse.headers().map())) | ||
.build(); | ||
return response; | ||
} | ||
|
||
/** | ||
* There is a bunch o headers that the http2 client do not allow to be set. | ||
* | ||
* @see jdk.internal.net.http.common.Utils.DISALLOWED_HEADERS_SET | ||
*/ | ||
private static final Set<String> DISALLOWED_HEADERS_SET; | ||
|
||
static { | ||
// A case insensitive TreeSet of strings. | ||
final TreeSet<String> treeSet = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); | ||
treeSet.addAll(Set.of("connection", "content-length", "date", "expect", "from", "host", | ||
"origin", "referer", "upgrade", "via", "warning")); | ||
DISALLOWED_HEADERS_SET = Collections.unmodifiableSet(treeSet); | ||
} | ||
|
||
private Map<String, Collection<String>> filterRestrictedHeaders(Map<String, Collection<String>> headers) { | ||
return headers.keySet() | ||
.stream() | ||
.filter(headerName -> !DISALLOWED_HEADERS_SET.contains(headerName)) | ||
.collect(Collectors.toMap( | ||
Function.identity(), | ||
headers::get)); | ||
} | ||
|
||
private Map<String, Collection<String>> castMapCollectType(Map<String, List<String>> map) { | ||
final Map<String, Collection<String>> result = new HashMap<>(); | ||
map.forEach((key, value) -> result.put(key, new HashSet<>(value))); | ||
return result; | ||
} | ||
|
||
private String[] asString(Map<String, Collection<String>> headers) { | ||
return headers.entrySet().stream() | ||
.flatMap(entry -> entry.getValue() | ||
.stream() | ||
.map(value -> Arrays.asList(entry.getKey(), value)) | ||
.flatMap(List::stream)) | ||
.collect(Collectors.toList()) | ||
.toArray(new String[0]); | ||
} | ||
|
||
} |
66 changes: 66 additions & 0 deletions
66
java11/src/test/java/feign/httpclient/test/Http2ClientTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/** | ||
* 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.httpclient.test; | ||
|
||
import feign.*; | ||
import feign.httpclient.Http2Client; | ||
import org.assertj.core.api.Assertions; | ||
import org.junit.Assert; | ||
import org.junit.Test; | ||
|
||
/** | ||
* Tests client-specific behavior, such as ensuring Content-Length is sent when specified. | ||
*/ | ||
public class Http2ClientTest { | ||
|
||
public interface TestInterface { | ||
@RequestLine("POST /?foo=bar&foo=baz&qux=") | ||
@Headers({"Foo: Bar", "Foo: Baz", "Qux: ", "Content-Type: text/plain"}) | ||
Response post(String var1); | ||
|
||
@RequestLine("POST /path/{to}/resource") | ||
@Headers({"Accept: text/plain"}) | ||
Response post(@Param("to") String var1, String var2); | ||
|
||
@RequestLine("GET /") | ||
@Headers({"Accept: text/plain"}) | ||
String get(); | ||
|
||
@RequestLine("PATCH /patch") | ||
@Headers({"Accept: text/plain"}) | ||
String patch(String var1); | ||
|
||
@RequestLine("POST") | ||
String noPostBody(); | ||
|
||
@RequestLine("PUT") | ||
String noPutBody(); | ||
|
||
@RequestLine("POST /?foo=bar&foo=baz&qux=") | ||
@Headers({"Foo: Bar", "Foo: Baz", "Qux: ", "Content-Type: {contentType}"}) | ||
Response postWithContentType(String var1, @Param("contentType") String var2); | ||
} | ||
|
||
@Test | ||
public void testPatch() throws Exception { | ||
TestInterface api = newBuilder().target(TestInterface.class, "https://nghttp2.org/httpbin/"); | ||
Assertions.assertThat(api.patch("")) | ||
.contains("https://nghttp2.org/httpbin/patch"); | ||
} | ||
|
||
public Feign.Builder newBuilder() { | ||
return Feign.builder().client(new Http2Client()); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters