Skip to content

Commit 1c10b95

Browse files
committed
#2 - Add HttpApi for obtaining client implementations of an interface
1 parent b3fa2ad commit 1c10b95

File tree

27 files changed

+575
-92
lines changed

27 files changed

+575
-92
lines changed

client/pom.xml

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<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">
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
34
<parent>
45
<artifactId>java11-oss</artifactId>
56
<groupId>org.avaje</groupId>
@@ -49,23 +50,23 @@
4950
</dependency>
5051

5152
<dependency>
52-
<groupId>io.dinject</groupId>
53-
<artifactId>dinject</artifactId>
54-
<version>2.3</version>
53+
<groupId>io.avaje</groupId>
54+
<artifactId>avaje-inject</artifactId>
55+
<version>3.0</version>
5556
<scope>test</scope>
5657
</dependency>
5758

5859
<dependency>
59-
<groupId>io.dinject</groupId>
60-
<artifactId>dinject-controller</artifactId>
61-
<version>1.21</version>
60+
<groupId>io.avaje</groupId>
61+
<artifactId>avaje-http-api</artifactId>
62+
<version>1.0</version>
6263
<scope>test</scope>
6364
</dependency>
6465

6566
<dependency>
66-
<groupId>io.dinject</groupId>
67-
<artifactId>controller-validator-hibernate</artifactId>
68-
<version>1.1</version>
67+
<groupId>io.avaje</groupId>
68+
<artifactId>avaje-http-hibernate-validator</artifactId>
69+
<version>1.0</version>
6970
<scope>test</scope>
7071
</dependency>
7172

@@ -79,19 +80,30 @@
7980
<!-- test annotation processors -->
8081

8182
<dependency>
82-
<groupId>io.dinject</groupId>
83-
<artifactId>dinject-generator</artifactId>
84-
<version>2.3</version>
85-
<scope>test</scope>
86-
</dependency>
87-
88-
<dependency>
89-
<groupId>io.dinject</groupId>
90-
<artifactId>javalin-generator</artifactId>
91-
<version>1.21</version>
83+
<groupId>io.avaje</groupId>
84+
<artifactId>avaje-inject-generator</artifactId>
85+
<version>3.0</version>
9286
<scope>test</scope>
9387
</dependency>
9488

9589
</dependencies>
9690

91+
<build>
92+
<plugins>
93+
<plugin>
94+
<artifactId>maven-surefire-plugin</artifactId>
95+
<version>3.0.0-M4</version>
96+
<configuration>
97+
<argLine>
98+
--add-modules com.fasterxml.jackson.databind
99+
--add-opens io.avaje.http.client/io.avaje.http.client=ALL-UNNAMED
100+
--add-opens io.avaje.http.client/org.example.webserver=ALL-UNNAMED
101+
--add-opens io.avaje.http.client/org.example.webserver=com.fasterxml.jackson.databind
102+
--add-opens io.avaje.http.client/org.example.github=com.fasterxml.jackson.databind
103+
</argLine>
104+
</configuration>
105+
</plugin>
106+
107+
</plugins>
108+
</build>
97109
</project>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package io.avaje.http.client;
2+
3+
import org.slf4j.Logger;
4+
import org.slf4j.LoggerFactory;
5+
6+
import java.util.HashMap;
7+
import java.util.Map;
8+
import java.util.ServiceLoader;
9+
10+
/**
11+
* Service loads the HttpApiProvider for HttpApi.
12+
*/
13+
class DHttpApi {
14+
15+
private static final Logger log = LoggerFactory.getLogger(DHttpApi.class);
16+
17+
private static final DHttpApi INSTANCE = new DHttpApi();
18+
19+
private final Map<Class<?>, HttpApiProvider<?>> providerMap = new HashMap<>();
20+
21+
DHttpApi() {
22+
init();
23+
}
24+
25+
@SuppressWarnings("rawtypes")
26+
void init() {
27+
for (HttpApiProvider apiProvider : ServiceLoader.load(HttpApiProvider.class)) {
28+
addProvider(apiProvider);
29+
}
30+
log.debug("providers for {}", providerMap.keySet());
31+
}
32+
33+
void addProvider(HttpApiProvider apiProvider) {
34+
providerMap.put(apiProvider.type(), apiProvider);
35+
}
36+
37+
@SuppressWarnings("unchecked")
38+
<T> T provideFor(Class<T> type, HttpClientContext clientContext) {
39+
final HttpApiProvider<T> apiProvider = (HttpApiProvider<T>) providerMap.get(type);
40+
if (apiProvider == null) {
41+
throw new IllegalArgumentException("No registered HttpApiProvider for type: " + type);
42+
}
43+
return apiProvider.provide(clientContext);
44+
}
45+
46+
static <T> T provide(Class<T> type, HttpClientContext clientContext) {
47+
return INSTANCE.provideFor(type, clientContext);
48+
}
49+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package io.avaje.http.client;
2+
3+
/**
4+
* Provides Http client service implementations for a given interface type.
5+
*/
6+
public interface HttpApi {
7+
8+
/**
9+
* Provide the http client implementation for the given interface type.
10+
*
11+
* @param interfaceType The interface type
12+
* @param clientContext The http client context used for executing the requests
13+
* @return The http client implementation for the given interface type
14+
*/
15+
static <T> T provide(Class<T> interfaceType, HttpClientContext clientContext) {
16+
return DHttpApi.provide(interfaceType, clientContext);
17+
}
18+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
11
package io.avaje.http.client;
22

3+
/**
4+
* Provides http client implementations for an interface.
5+
*
6+
* @param <T> The interface type
7+
*/
38
public interface HttpApiProvider<T> {
49

10+
/**
11+
* Return the interface type this API implements.
12+
*/
13+
Class<T> type();
14+
15+
/**
16+
* Return the provided implementation of the API.
17+
*/
518
T provide(HttpClientContext client);
619

720
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module io.avaje.http.client {
2+
3+
uses io.avaje.http.client.HttpApiProvider;
4+
5+
requires transitive java.net.http;
6+
requires transitive org.slf4j;
7+
requires static com.fasterxml.jackson.databind;
8+
9+
exports io.avaje.http.client;
10+
}

client/src/test/java/io/avaje/http/client/BaseWebTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package io.avaje.http.client;
22

33
import com.fasterxml.jackson.databind.ObjectMapper;
4-
import io.javalin.Javalin;
54
import org.example.webserver.App;
5+
import io.javalin.Javalin;
66
import org.junit.jupiter.api.AfterAll;
77
import org.junit.jupiter.api.BeforeAll;
88

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package io.avaje.http.client;
2+
3+
import com.fasterxml.jackson.databind.DeserializationFeature;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import org.example.github.Repo;
6+
import org.example.github.Simple;
7+
import org.example.github.SimpleHttpClient;
8+
import org.junit.jupiter.api.Test;
9+
10+
import java.util.List;
11+
12+
import static org.assertj.core.api.Assertions.assertThat;
13+
14+
public class DHttpApiTest {
15+
16+
@Test
17+
void test_github_listRepos() {
18+
19+
JacksonBodyAdapter bodyAdapter = new JacksonBodyAdapter(new ObjectMapper()
20+
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false));
21+
22+
final HttpClientContext clientContext = HttpClientContext.newBuilder()
23+
.withBaseUrl("https://api.github.com")
24+
.withBodyAdapter(bodyAdapter)
25+
.build();
26+
27+
DHttpApi httpApi = new DHttpApi();
28+
httpApi.addProvider(new SimpleHttpClient.Provider());
29+
final Simple simple = httpApi.provideFor(Simple.class, clientContext);
30+
31+
final List<Repo> repos = simple.listRepos("rbygrave", "junk");
32+
assertThat(repos).isNotEmpty();
33+
}
34+
35+
}

client/src/test/java/io/avaje/http/client/HelloControllerTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,6 @@ void postForm_asVoid_invokesValidation_expect_badRequest_extractError() {
154154

155155
@Test
156156
void postForm_asBytes_validation_expect_badRequest_extractError() {
157-
158157
try {
159158
clientContext.request()
160159
.path("hello/saveform")
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package org.example.github;
2+
3+
import com.fasterxml.jackson.databind.DeserializationFeature;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import io.avaje.http.client.HttpApi;
6+
import io.avaje.http.client.HttpClientContext;
7+
import io.avaje.http.client.JacksonBodyAdapter;
8+
import org.junit.jupiter.api.Disabled;
9+
import org.junit.jupiter.api.Test;
10+
11+
import java.util.List;
12+
13+
import static org.assertj.core.api.Assertions.assertThat;
14+
15+
public class GithubTest {
16+
17+
@Test @Disabled
18+
void test() {
19+
20+
JacksonBodyAdapter bodyAdapter = new JacksonBodyAdapter(new ObjectMapper()
21+
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false));
22+
23+
final HttpClientContext clientContext = HttpClientContext.newBuilder()
24+
.withBaseUrl("https://api.github.com")
25+
.withBodyAdapter(bodyAdapter)
26+
.build();
27+
28+
final Simple simple = HttpApi.provide(Simple.class, clientContext);
29+
30+
final List<Repo> repos = simple.listRepos("rbygrave", "junk");
31+
assertThat(repos).isNotEmpty();
32+
}
33+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package org.example.github;
2+
3+
public class Repo {
4+
public long id;
5+
public String name;
6+
}

0 commit comments

Comments
 (0)