Skip to content

Commit c26ebf1

Browse files
authored
Merge pull request #182 from SentryMan/body
(Client) Support Generic Body Type
2 parents cec0011 + f430e73 commit c26ebf1

File tree

8 files changed

+71
-27
lines changed

8 files changed

+71
-27
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ public interface BodyAdapter {
1717
*/
1818
<T> BodyWriter<T> beanWriter(Class<?> type);
1919

20+
/**
21+
* Return a BodyWriter to write beans of this type as request content.
22+
*
23+
* @param type The type of the bean this writer is for
24+
*/
25+
default <T> BodyWriter<T> beanWriter(ParameterizedType type) {
26+
27+
throw new UnsupportedOperationException("Parameterized types not supported for this adapter");
28+
}
29+
2030
/**
2131
* Return a BodyReader to read response content and convert to a bean.
2232
*

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,10 @@ <T> BodyContent write(T bean, Class<?> type, String contentType) {
269269
return bodyAdapter.beanWriter(type).write(bean, contentType);
270270
}
271271

272+
<T> BodyContent write(T bean, ParameterizedType type, String contentType) {
273+
return bodyAdapter.beanWriter(type).write(bean, contentType);
274+
}
275+
272276
<T> BodyReader<T> beanReader(Class<T> type) {
273277
return bodyAdapter.beanReader(type);
274278
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,12 @@ public HttpClientRequest body(Object bean, Class<?> type) {
281281
return body(bean, type, null);
282282
}
283283

284+
@Override
285+
public HttpClientRequest body(Object bean, ParameterizedType type) {
286+
encodedRequestBody = context.write(bean, type, null);
287+
return this;
288+
}
289+
284290
@Override
285291
public HttpClientRequest body(Object bean, Class<?> type, String contentType) {
286292
encodedRequestBody = context.write(bean, type, contentType);

http-client/src/main/java/io/avaje/http/client/HttpClientRequest.java

Lines changed: 14 additions & 0 deletions
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.HttpRequest;
56
import java.net.http.HttpResponse;
67
import java.nio.file.Path;
@@ -312,6 +313,19 @@ default HttpClientRequest queryParam(String name, Collection<String> values) {
312313
*/
313314
HttpClientRequest body(Object bean, Class<?> type);
314315

316+
/**
317+
* Set the body as a bean additionally specifying the type that will be
318+
* used to serialise the content (e.g. JsonbAdapter).
319+
* <p>
320+
* Specifying the type allows the bean instance to be a type that extends
321+
* a type that is known to JsonbAdapter / the body content adapter used.
322+
*
323+
* @param bean The body content as an instance
324+
* @param type The parameterized type used by the body content adapter to write the body content
325+
* @return The request being built
326+
*/
327+
HttpClientRequest body(Object bean, ParameterizedType type);
328+
315329
/**
316330
* Set the body as a bean with the given content type and additionally specifying
317331
* the type that will be used to serialise the content (e.g. JsonbAdapter).

http-client/src/main/java/io/avaje/http/client/JsonbBodyAdapter.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ public <T> BodyWriter<T> beanWriter(Class<?> cls) {
4747
return (BodyWriter<T>) beanWriterCache.computeIfAbsent(cls, aClass -> new JWriter<>(jsonb.type(cls)));
4848
}
4949

50+
@SuppressWarnings("unchecked")
51+
@Override
52+
public <T> BodyWriter<T> beanWriter(ParameterizedType type) {
53+
return (BodyWriter<T>) beanWriterCache.computeIfAbsent(type, aClass -> new JWriter<>(jsonb.type(type)));
54+
}
55+
5056
@SuppressWarnings("unchecked")
5157
@Override
5258
public <T> BodyReader<T> beanReader(Class<T> cls) {

http-generator-client/src/main/java/io/avaje/http/generator/client/ClientMethodWriter.java

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,12 @@ private void writeEnd() {
107107
String known = KNOWN_RESPONSE.get(returnType.full());
108108
if (known != null) {
109109
writer.append(" %s", known).eol();
110+
} else if (COMPLETABLE_FUTURE.equals(returnType.mainType())) {
111+
writeAsyncResponse();
112+
} else if (HTTP_CALL.equals(returnType.mainType())) {
113+
writeCallResponse();
110114
} else {
111-
if (COMPLETABLE_FUTURE.equals(returnType.mainType())) {
112-
writeAsyncResponse();
113-
} else if (HTTP_CALL.equals(returnType.mainType())) {
114-
writeCallResponse();
115-
} else {
116-
writeSyncResponse();
117-
}
115+
writeSyncResponse();
118116
}
119117
}
120118
writer.append(" }").eol().eol();
@@ -141,27 +139,32 @@ private void writeResponse(UType type) {
141139
if (isList(mainType)) {
142140
writer.append(".list(");
143141
writeGeneric(param1);
142+
writer.append(");").eol();
144143
} else if (isStream(mainType)) {
145144
writer.append(".stream(");
146145
writeGeneric(param1);
146+
writer.append(");").eol();
147147
} else if (isHttpResponse(mainType)) {
148148
if (bodyHandlerParam == null) {
149-
UType paramType = type.paramRaw();
150-
if (paramType.mainType().equals("java.util.List")) {
149+
final UType paramType = type.paramRaw();
150+
if ("java.util.List".equals(paramType.mainType())) {
151151
writer.append(".asList(");
152152
writeGeneric(paramType.paramRaw());
153-
} else if (paramType.mainType().equals("java.util.stream.Stream")) {
153+
} else if ("java.util.stream.Stream".equals(paramType.mainType())) {
154154
writer.append(".asStream(");
155155
writeGeneric(paramType.paramRaw());
156156
} else {
157157
writer.append(".as(");
158158
writeGeneric(paramType);
159159
}
160+
writer.append(");").eol();
160161
} else {
161-
writer.append(".handler(%s);", bodyHandlerParam.name()).eol(); }
162+
writer.append(".handler(%s);", bodyHandlerParam.name()).eol();
163+
}
162164
} else {
163165
writer.append(".bean(");
164166
writeGeneric(type);
167+
writer.append(");").eol();
165168
}
166169
}
167170

@@ -177,19 +180,16 @@ void writeGeneric(UType type) {
177180
} else {
178181
writer.append("%s.class", Util.shortName(type.mainType()));
179182
}
180-
writer.append(");").eol();
181183
}
182184

183185
private void writeQueryParams(PathSegments pathSegments) {
184-
for (MethodParam param : method.params()) {
185-
ParamType paramType = param.paramType();
186-
if (paramType == ParamType.QUERYPARAM) {
187-
if (pathSegments.segment(param.paramName()) == null) {
188-
if (isMap(param)) {
189-
writer.append(" .queryParam(%s)", param.name()).eol();
190-
} else {
191-
writer.append(" .queryParam(\"%s\", %s)", param.paramName(), param.name()).eol();
192-
}
186+
for (final MethodParam param : method.params()) {
187+
final ParamType paramType = param.paramType();
188+
if (paramType == ParamType.QUERYPARAM && pathSegments.segment(param.paramName()) == null) {
189+
if (isMap(param)) {
190+
writer.append(" .queryParam(%s)", param.name()).eol();
191+
} else {
192+
writer.append(" .queryParam(\"%s\", %s)", param.paramName(), param.name()).eol();
193193
}
194194
}
195195
}
@@ -251,7 +251,9 @@ private void writeBody() {
251251
for (MethodParam param : method.params()) {
252252
ParamType paramType = param.paramType();
253253
if (paramType == ParamType.BODY) {
254-
writer.append(" .body(%s, %s.class)", param.name(), param.utype().shortType()).eol();
254+
writer.append(" .body(%s, ", param.name());
255+
writeGeneric(param.utype());
256+
writer.append(")").eol();
255257
}
256258
}
257259
}
@@ -278,19 +280,19 @@ private boolean isMap(MethodParam param) {
278280
}
279281

280282
private boolean isMap(String type0) {
281-
return type0.equals("java.util.Map");
283+
return "java.util.Map".equals(type0);
282284
}
283285

284286
private boolean isList(String type0) {
285-
return type0.equals("java.util.List");
287+
return "java.util.List".equals(type0);
286288
}
287289

288290
private boolean isStream(String type0) {
289-
return type0.equals("java.util.stream.Stream");
291+
return "java.util.stream.Stream".equals(type0);
290292
}
291293

292294
private boolean isHttpResponse(String type0) {
293-
return type0.equals("java.net.http.HttpResponse");
295+
return "java.net.http.HttpResponse".equals(type0);
294296
}
295297

296298
}

tests/test-javalin-jsonb/src/main/java/org/example/myapp/web/test/ServerType.java renamed to tests/test-javalin-jsonb/src/main/java/org/example/myapp/web/ServerType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.example.myapp.web.test;
1+
package org.example.myapp.web;
22

33
public enum ServerType {
44
PROXY,

tests/test-javalin-jsonb/src/main/java/org/example/myapp/web/test/TestController2.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import java.util.Map;
66
import java.util.Set;
77

8+
import org.example.myapp.web.ServerType;
9+
810
import io.avaje.http.api.Controller;
911
import io.avaje.http.api.Default;
1012
import io.avaje.http.api.Form;

0 commit comments

Comments
 (0)