Skip to content

Commit 58bd05f

Browse files
authored
Merge pull request #56 from SentryMan/master
Add support for Jsonb generics
2 parents ab81c8c + 61619e5 commit 58bd05f

12 files changed

+292
-22
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ public final class ExampleRetry implements RetryHandler {
310310
311311
final var code = response.statusCode();
312312
313-
if (retryCount >= MAX_RETRIES || code >= 400) {
313+
if (retryCount >= MAX_RETRIES || code <= 400) {
314314
315315
return false;
316316
}

client/pom.xml

+5-5
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@
3939
<dependency>
4040
<groupId>io.avaje</groupId>
4141
<artifactId>avaje-jsonb</artifactId>
42-
<version>1.0-RC1</version>
42+
<version>1.1-RC2</version>
4343
<optional>true</optional>
4444
</dependency>
4545

4646
<dependency>
4747
<groupId>io.avaje</groupId>
4848
<artifactId>avaje-inject</artifactId>
49-
<version>8.6</version>
49+
<version>8.10</version>
5050
<optional>true</optional>
5151
</dependency>
5252

@@ -76,14 +76,14 @@
7676
<dependency>
7777
<groupId>io.javalin</groupId>
7878
<artifactId>javalin</artifactId>
79-
<version>4.1.1</version>
79+
<version>5.2.0</version>
8080
<scope>test</scope>
8181
</dependency>
8282

8383
<dependency>
8484
<groupId>io.avaje</groupId>
8585
<artifactId>avaje-http-api</artifactId>
86-
<version>1.16</version>
86+
<version>1.20</version>
8787
<scope>test</scope>
8888
</dependency>
8989

@@ -125,7 +125,7 @@
125125
<path>
126126
<groupId>io.avaje</groupId>
127127
<artifactId>avaje-inject-generator</artifactId>
128-
<version>8.6</version>
128+
<version>8.10</version>
129129
</path>
130130
</annotationProcessorPaths>
131131
</configuration>

client/src/main/java/io/avaje/http/client/BodyAdapter.java

+19
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.avaje.http.client;
22

3+
import java.lang.reflect.ParameterizedType;
34
import java.util.List;
45

56
/**
@@ -23,11 +24,29 @@ public interface BodyAdapter {
2324
*/
2425
<T> BodyReader<T> beanReader(Class<T> type);
2526

27+
/**
28+
* Return a BodyReader to read response content and convert to a bean.
29+
*
30+
* @param type The bean type to convert the content to.
31+
*/
32+
default <T> BodyReader<T> beanReader(ParameterizedType type) {
33+
throw new UnsupportedOperationException("Parameterized types not supported for this adapter");
34+
}
35+
36+
2637
/**
2738
* Return a BodyReader to read response content and convert to a list of beans.
2839
*
2940
* @param type The bean type to convert the content to.
3041
*/
3142
<T> BodyReader<List<T>> listReader(Class<T> type);
3243

44+
/**
45+
* Return a BodyReader to read response content and convert to a list of beans.
46+
*
47+
* @param type The bean type to convert the content to.
48+
*/
49+
default <T> BodyReader<List<T>> listReader(ParameterizedType type) {
50+
throw new UnsupportedOperationException("Parameterized types not supported for this adapter");
51+
}
3352
}

client/src/main/java/io/avaje/http/client/DHttpAsync.java

+22
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.avaje.http.client;
22

33
import java.io.InputStream;
4+
import java.lang.reflect.ParameterizedType;
45
import java.net.http.HttpResponse;
56
import java.util.List;
67
import java.util.concurrent.CompletableFuture;
@@ -78,4 +79,25 @@ public <E> CompletableFuture<Stream<E>> stream(Class<E> type) {
7879
.performSendAsync(false, HttpResponse.BodyHandlers.ofLines())
7980
.thenApply(httpResponse -> request.asyncStream(type, httpResponse));
8081
}
82+
83+
@Override
84+
public <E> CompletableFuture<E> bean(ParameterizedType type) {
85+
return request
86+
.performSendAsync(true, HttpResponse.BodyHandlers.ofByteArray())
87+
.thenApply(httpResponse -> request.asyncBean(type, httpResponse));
88+
}
89+
90+
@Override
91+
public <E> CompletableFuture<List<E>> list(ParameterizedType type) {
92+
return request
93+
.performSendAsync(true, HttpResponse.BodyHandlers.ofByteArray())
94+
.thenApply(httpResponse -> request.asyncList(type, httpResponse));
95+
}
96+
97+
@Override
98+
public <E> CompletableFuture<Stream<E>> stream(ParameterizedType type) {
99+
return request
100+
.performSendAsync(false, HttpResponse.BodyHandlers.ofLines())
101+
.thenApply(httpResponse -> request.asyncStream(type, httpResponse));
102+
}
81103
}

client/src/main/java/io/avaje/http/client/DHttpCall.java

+61-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.avaje.http.client;
22

33
import java.io.InputStream;
4+
import java.lang.reflect.ParameterizedType;
45
import java.net.http.HttpResponse;
56
import java.util.List;
67
import java.util.concurrent.CompletableFuture;
@@ -64,6 +65,21 @@ public <E> HttpCall<Stream<E>> stream(Class<E> type) {
6465
return new CallStream<>(type);
6566
}
6667

68+
@Override
69+
public <E> HttpCall<E> bean(ParameterizedType type) {
70+
return new CallBean<>(type);
71+
}
72+
73+
@Override
74+
public <E> HttpCall<List<E>> list(ParameterizedType type) {
75+
return new CallList<>(type);
76+
}
77+
78+
@Override
79+
public <E> HttpCall<Stream<E>> stream(ParameterizedType type) {
80+
return new CallStream<>(type);
81+
}
82+
6783
private class CallVoid implements HttpCall<HttpResponse<Void>> {
6884
@Override
6985
public HttpResponse<Void> execute() {
@@ -132,46 +148,85 @@ public CompletableFuture<HttpResponse<InputStream>> async() {
132148

133149
private class CallBean<E> implements HttpCall<E> {
134150
private final Class<E> type;
151+
private final ParameterizedType genericType;
152+
private final boolean isGeneric;
153+
135154
CallBean(Class<E> type) {
155+
this.isGeneric = false;
136156
this.type = type;
157+
this.genericType = null;
137158
}
159+
160+
CallBean(ParameterizedType type) {
161+
this.isGeneric = true;
162+
this.type = null;
163+
this.genericType = type;
164+
}
165+
138166
@Override
139167
public E execute() {
140-
return request.bean(type);
168+
return isGeneric ? request.bean(genericType) : request.bean(type);
141169
}
170+
142171
@Override
143172
public CompletableFuture<E> async() {
144-
return request.async().bean(type);
173+
return isGeneric ? request.async().bean(genericType) : request.async().bean(type);
145174
}
146175
}
147176

148177
private class CallList<E> implements HttpCall<List<E>> {
149178
private final Class<E> type;
179+
private final ParameterizedType genericType;
180+
private final boolean isGeneric;
181+
150182
CallList(Class<E> type) {
183+
this.isGeneric = false;
151184
this.type = type;
185+
this.genericType = null;
152186
}
187+
188+
CallList(ParameterizedType type) {
189+
this.isGeneric = true;
190+
this.type = null;
191+
this.genericType = type;
192+
}
193+
153194
@Override
154195
public List<E> execute() {
155-
return request.list(type);
196+
return isGeneric ? request.list(genericType) : request.list(type);
156197
}
198+
157199
@Override
158200
public CompletableFuture<List<E>> async() {
159-
return request.async().list(type);
201+
return isGeneric ? request.async().list(genericType) : request.async().list(type);
160202
}
161203
}
162204

163205
private class CallStream<E> implements HttpCall<Stream<E>> {
164206
private final Class<E> type;
207+
private final ParameterizedType genericType;
208+
private final boolean isGeneric;
209+
165210
CallStream(Class<E> type) {
211+
this.isGeneric = false;
166212
this.type = type;
213+
this.genericType = null;
214+
}
215+
216+
CallStream(ParameterizedType type) {
217+
this.isGeneric = true;
218+
this.type = null;
219+
this.genericType = type;
167220
}
221+
168222
@Override
169223
public Stream<E> execute() {
170-
return request.stream(type);
224+
return isGeneric ? request.stream(genericType) : request.stream(type);
171225
}
226+
172227
@Override
173228
public CompletableFuture<Stream<E>> async() {
174-
return request.async().stream(type);
229+
return isGeneric ? request.async().stream(genericType) : request.async().stream(type);
175230
}
176231
}
177232

client/src/main/java/io/avaje/http/client/DHttpClientContext.java

+14
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.io.IOException;
44
import java.lang.reflect.Constructor;
5+
import java.lang.reflect.ParameterizedType;
56
import java.net.http.HttpClient;
67
import java.net.http.HttpHeaders;
78
import java.net.http.HttpRequest;
@@ -273,6 +274,10 @@ <T> BodyReader<T> beanReader(Class<T> cls) {
273274
return bodyAdapter.beanReader(cls);
274275
}
275276

277+
<T> BodyReader<T> beanReader(ParameterizedType cls) {
278+
return bodyAdapter.beanReader(cls);
279+
}
280+
276281
<T> T readBean(Class<T> cls, BodyContent content) {
277282
return bodyAdapter.beanReader(cls).read(content);
278283
}
@@ -281,6 +286,15 @@ <T> List<T> readList(Class<T> cls, BodyContent content) {
281286
return bodyAdapter.listReader(cls).read(content);
282287
}
283288

289+
@SuppressWarnings("unchecked")
290+
<T> T readBean(ParameterizedType cls, BodyContent content) {
291+
return (T) bodyAdapter.beanReader(cls).read(content);
292+
}
293+
294+
<T> List<T> readList(ParameterizedType cls, BodyContent content) {
295+
return (List<T>) bodyAdapter.listReader(cls).read(content);
296+
}
297+
284298
void afterResponse(DHttpClientRequest request) {
285299
metricResTotal.add(1);
286300
metricResMicros.add(request.responseTimeMicros());

client/src/main/java/io/avaje/http/client/DHttpClientRequest.java

+49-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import javax.net.ssl.SSLSession;
44
import java.io.FileNotFoundException;
55
import java.io.InputStream;
6+
import java.lang.reflect.ParameterizedType;
67
import java.net.URI;
78
import java.net.URLEncoder;
89
import java.net.http.HttpClient;
@@ -433,7 +434,7 @@ public <T> List<T> list(Class<T> cls) {
433434
readResponseContent();
434435
return context.readList(cls, encodedResponseBody);
435436
}
436-
437+
437438
@Override
438439
public <T> Stream<T> stream(Class<T> cls) {
439440
final HttpResponse<Stream<String>> res = handler(HttpResponse.BodyHandlers.ofLines());
@@ -445,6 +446,31 @@ public <T> Stream<T> stream(Class<T> cls) {
445446
return res.body().map(bodyReader::readBody);
446447
}
447448

449+
450+
@Override
451+
public <T> T bean(ParameterizedType cls) {
452+
readResponseContent();
453+
return context.readBean(cls, encodedResponseBody);
454+
}
455+
456+
@Override
457+
public <T> List<T> list(ParameterizedType cls) {
458+
readResponseContent();
459+
return context.readList(cls, encodedResponseBody);
460+
}
461+
462+
463+
@Override
464+
public <T> Stream<T> stream(ParameterizedType cls) {
465+
final HttpResponse<Stream<String>> res = handler(HttpResponse.BodyHandlers.ofLines());
466+
this.httpResponse = res;
467+
if (res.statusCode() >= 300) {
468+
throw new HttpException(res, context);
469+
}
470+
final BodyReader<T> bodyReader = context.beanReader(cls);
471+
return res.body().map(bodyReader::readBody);
472+
}
473+
448474
@Override
449475
public <T> HttpResponse<T> handler(HttpResponse.BodyHandler<T> responseHandler) {
450476
final HttpResponse<T> response = sendWith(responseHandler);
@@ -506,6 +532,28 @@ protected <E> Stream<E> asyncStream(Class<E> type, HttpResponse<Stream<String>>
506532
return response.body().map(bodyReader::readBody);
507533
}
508534

535+
protected <E> E asyncBean(ParameterizedType type, HttpResponse<byte[]> response) {
536+
afterAsyncEncoded(response);
537+
return context.readBean(type, encodedResponseBody);
538+
}
539+
540+
protected <E> List<E> asyncList(ParameterizedType type, HttpResponse<byte[]> response) {
541+
afterAsyncEncoded(response);
542+
return context.readList(type, encodedResponseBody);
543+
}
544+
545+
protected <E> Stream<E> asyncStream(
546+
ParameterizedType type, HttpResponse<Stream<String>> response) {
547+
responseTimeNanos = System.nanoTime() - startAsyncNanos;
548+
httpResponse = response;
549+
context.afterResponse(this);
550+
if (response.statusCode() >= 300) {
551+
throw new HttpException(response, context);
552+
}
553+
final BodyReader<E> bodyReader = context.beanReader(type);
554+
return response.body().map(bodyReader::readBody);
555+
}
556+
509557
private void afterAsyncEncoded(HttpResponse<byte[]> response) {
510558
responseTimeNanos = System.nanoTime() - startAsyncNanos;
511559
httpResponse = response;

client/src/main/java/io/avaje/http/client/HttpAsyncResponse.java

+26
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.avaje.http.client;
22

33
import java.io.InputStream;
4+
import java.lang.reflect.ParameterizedType;
45
import java.net.http.HttpResponse;
56
import java.util.List;
67
import java.util.concurrent.CompletableFuture;
@@ -334,4 +335,29 @@ default <E> CompletableFuture<HttpResponse<E>> withHandler(HttpResponse.BodyHand
334335
* @return The CompletableFuture of the response
335336
*/
336337
<E> CompletableFuture<Stream<E>> stream(Class<E> type);
338+
339+
/**
340+
* Process expecting a bean response body (typically from json content).
341+
*
342+
* @param type The parameterized type to convert the content to
343+
* @return The CompletableFuture of the response
344+
*/
345+
<E> CompletableFuture<E> bean(ParameterizedType type);
346+
347+
/**
348+
* Process expecting a list of beans response body (typically from json content).
349+
*
350+
* @param type The parameterized type to convert the content to
351+
* @return The CompletableFuture of the response
352+
*/
353+
<E> CompletableFuture<List<E>> list(ParameterizedType type);
354+
355+
/**
356+
* Process response as a stream of beans (x-json-stream).
357+
*
358+
* @param type The parameterized type to convert the content to
359+
* @return The CompletableFuture of the response
360+
*/
361+
<E> CompletableFuture<Stream<E>> stream(ParameterizedType type);
362+
337363
}

0 commit comments

Comments
 (0)