Skip to content
This repository was archived by the owner on Mar 3, 2026. It is now read-only.

Commit 464d8c2

Browse files
committed
Add test for BodyPart or Body param
1 parent ffc2669 commit 464d8c2

2 files changed

Lines changed: 120 additions & 5 deletions

File tree

jooby-core/src/main/java/jooby/Jooby.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.text.SimpleDateFormat;
1111
import java.time.format.DateTimeFormatter;
1212
import java.util.LinkedHashSet;
13+
import java.util.LinkedList;
1314
import java.util.List;
1415
import java.util.Locale;
1516
import java.util.Map.Entry;
@@ -396,10 +397,17 @@ public abstract void configure(@Nonnull Mode mode, @Nonnull Config config,
396397

397398
private Err.Handler err;
398399

400+
private List<BodyConverter> converters = new LinkedList<>();
401+
399402
{
400403
use(new Jetty());
401404
}
402405

406+
public Jooby use(final BodyConverter converter) {
407+
this.converters.add(requireNonNull(converter, "A body converter is required."));
408+
return this;
409+
}
410+
403411
public Route.Definition use(final Filter filter) {
404412
return use("*", filter);
405413
}
@@ -765,7 +773,7 @@ public void configure(final Binder binder) {
765773
binder.bind(DecimalFormat.class).toInstance(numberFormat);
766774

767775
// bind readers & writers
768-
Multibinder<BodyConverter> converters = Multibinder
776+
Multibinder<BodyConverter> converterBinder = Multibinder
769777
.newSetBinder(binder, BodyConverter.class);
770778

771779
// Routes
@@ -788,6 +796,9 @@ public void configure(final Binder binder) {
788796
binder.bind(File.class).annotatedWith(Names.named("java.io.tmpdir"))
789797
.toInstance(new File(config.getString("java.io.tmpdir")));
790798

799+
// converters
800+
converters.forEach(it -> converterBinder.addBinding().toInstance(it));
801+
791802
// modules, routes and websockets
792803
bag.forEach(candidate -> {
793804
if (candidate instanceof Jooby.Module) {
@@ -806,10 +817,10 @@ public void configure(final Binder binder) {
806817
// Singleton routes
807818
singletonRoutes.forEach(routeClass -> binder.bind(routeClass).in(Scopes.SINGLETON));
808819

809-
converters.addBinding().toInstance(FallbackBodyConverter.COPY_TEXT);
810-
converters.addBinding().toInstance(FallbackBodyConverter.COPY_BYTES);
811-
converters.addBinding().toInstance(FallbackBodyConverter.READ_TEXT);
812-
converters.addBinding().toInstance(FallbackBodyConverter.TO_HTML);
820+
converterBinder.addBinding().toInstance(FallbackBodyConverter.COPY_TEXT);
821+
converterBinder.addBinding().toInstance(FallbackBodyConverter.COPY_BYTES);
822+
converterBinder.addBinding().toInstance(FallbackBodyConverter.READ_TEXT);
823+
converterBinder.addBinding().toInstance(FallbackBodyConverter.TO_HTML);
813824

814825
// err
815826
if (err == null) {
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package jooby;
2+
3+
import static org.junit.Assert.assertEquals;
4+
5+
import java.io.IOException;
6+
import java.io.Writer;
7+
import java.util.List;
8+
9+
import jooby.mvc.POST;
10+
import jooby.mvc.Path;
11+
12+
import org.apache.http.client.fluent.Request;
13+
import org.apache.http.entity.ContentType;
14+
import org.apache.http.entity.mime.MultipartEntityBuilder;
15+
import org.junit.Test;
16+
17+
import com.google.common.collect.ImmutableList;
18+
import com.google.common.io.CharSink;
19+
import com.google.common.io.CharStreams;
20+
import com.google.inject.TypeLiteral;
21+
22+
public class BodyParamFeature extends ServerFeature {
23+
24+
private static class Bean {
25+
26+
}
27+
28+
@Path("/r")
29+
public static class Resource {
30+
31+
@Path("/body")
32+
@POST
33+
public Bean body(final Bean param) throws IOException {
34+
return param;
35+
}
36+
37+
}
38+
39+
{
40+
41+
use(new BodyConverter() {
42+
43+
@Override
44+
public void write(final Object body, final BodyWriter writer) throws Exception {
45+
writer.text(out -> new CharSink() {
46+
@Override
47+
public Writer openStream() throws IOException {
48+
return out;
49+
}
50+
}.write("{}"));
51+
}
52+
53+
@Override
54+
public List<MediaType> types() {
55+
return ImmutableList.of(MediaType.json);
56+
}
57+
58+
@SuppressWarnings("unchecked")
59+
@Override
60+
public <T> T read(final TypeLiteral<T> type, final BodyReader reader) throws Exception {
61+
String body = reader.text(in ->CharStreams.toString(in));
62+
assertEquals("{}", body);
63+
return (T) new Bean();
64+
}
65+
66+
@Override
67+
public boolean canWrite(final Class<?> type) {
68+
return type == Bean.class;
69+
}
70+
71+
@Override
72+
public boolean canRead(final TypeLiteral<?> type) {
73+
return type.getRawType() == Bean.class;
74+
}
75+
});
76+
77+
post("/body", (req, resp) -> {
78+
Bean bean = req.param("param").to(Bean.class);
79+
resp.send(bean);
80+
});
81+
82+
use(Resource.class);
83+
}
84+
85+
@Test
86+
public void multipart() throws Exception {
87+
assertEquals("{}",
88+
Request
89+
.Post(uri("body").build())
90+
.body(
91+
MultipartEntityBuilder
92+
.create()
93+
.addTextBody("param", "{}", ContentType.APPLICATION_JSON)
94+
.build()).execute().returnContent().asString());
95+
96+
assertEquals("{}",
97+
Request.Post(uri("r", "body").build())
98+
.body(MultipartEntityBuilder.create()
99+
.addTextBody("param", "{}", ContentType.APPLICATION_JSON)
100+
.build()).execute().returnContent().asString());
101+
102+
}
103+
104+
}

0 commit comments

Comments
 (0)