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

Commit 0c3adf3

Browse files
committed
general improvements
* support parsing on form field by setting a content type * improve err handling on missing params * fix an error on no application/json request on Json parsers (Gson and Jackson) * add unit tests but also integration tests * expand system property from maven plugin to jooby app
1 parent 51d66e6 commit 0c3adf3

File tree

35 files changed

+718
-84
lines changed

35 files changed

+718
-84
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.jooby;
2+
3+
import org.jooby.test.ServerFeature;
4+
import org.junit.Test;
5+
6+
public class MissingParamFeature extends ServerFeature {
7+
8+
{
9+
get("/missing", req -> req.param("p1").value());
10+
}
11+
12+
@Test
13+
public void missingParam() throws Exception {
14+
request()
15+
.get("/missing")
16+
.expect(400);
17+
}
18+
}

coverage-report/src/test/java/org/jooby/MultipartFormParamFeature.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import java.util.Optional;
1010
import java.util.stream.Collectors;
1111

12-
import org.jooby.Upload;
1312
import org.jooby.mvc.POST;
1413
import org.jooby.mvc.Path;
1514
import org.jooby.test.ServerFeature;
@@ -63,7 +62,7 @@ public String optional(final Optional<Upload> upload) throws IOException {
6362
post("/form", (req, resp) -> {
6463
String name = req.param("name").value();
6564
int age = req.param("age").intValue();
66-
Upload upload = req.param("myfile").to(Upload.class);
65+
Upload upload = req.param("myfile").toUpload();
6766
resp.send(name + " " + age + " " + upload.name() + " " + upload.type());
6867
});
6968

@@ -79,7 +78,7 @@ public String optional(final Optional<Upload> upload) throws IOException {
7978
});
8079

8180
post("/form/use/file", (req, rsp) -> {
82-
Upload upload = req.param("myfile").to(Upload.class);
81+
Upload upload = req.param("myfile").toUpload();
8382
File file = upload.file();
8483
try (Upload u = upload) {
8584
assertEquals("p=1", Files.readAllLines(file.toPath()).stream()

coverage-report/src/test/java/org/jooby/ParamPrecedenceFeature.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ public class ParamPrecedenceFeature extends ServerFeature {
1313
// path param
1414
assertEquals("a", req.param("name").value());
1515
// query param
16-
assertEquals("b", req.param("name").toList(String.class).get(1));
16+
assertEquals("b", req.param("name").toList().get(1));
1717
// body param
18-
assertEquals("c", req.param("name").toList(String.class).get(2));
19-
resp.send(req.param("name").toList(String.class));
18+
assertEquals("c", req.param("name").toList().get(2));
19+
resp.send(req.param("name").toList());
2020
});
2121

2222
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package org.jooby.gson;
2+
3+
import org.jooby.MediaType;
4+
import org.jooby.json.Gzon;
5+
import org.jooby.test.ServerFeature;
6+
import org.junit.Test;
7+
8+
public class GsonFormParamFeature extends ServerFeature {
9+
10+
public static class User {
11+
12+
public String name;
13+
}
14+
15+
{
16+
17+
use(new Gzon());
18+
19+
post("/json/form/param", req ->
20+
req.param("user").to(User.class, MediaType.json));
21+
22+
}
23+
24+
@Test
25+
public void postParam() throws Exception {
26+
request()
27+
.post("/json/form/param")
28+
.form()
29+
.add("user", "{\"name\":\"X\"}")
30+
.expect("{\"name\":\"X\"}");
31+
}
32+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package org.jooby.jackson;
2+
3+
import org.jooby.json.Jackson;
4+
import org.jooby.test.ServerFeature;
5+
import org.junit.Test;
6+
7+
public class JsonFormParamFeature extends ServerFeature {
8+
9+
public static class User {
10+
11+
public String name;
12+
}
13+
14+
{
15+
16+
use(new Jackson());
17+
18+
post("/json/form/param", req ->
19+
req.param("user").to(User.class, "json"));
20+
21+
}
22+
23+
@Test
24+
public void postParam() throws Exception {
25+
request()
26+
.post("/json/form/param")
27+
.form()
28+
.add("user", "{\"name\":\"X\"}")
29+
.expect("{\"name\":\"X\"}");
30+
}
31+
}

jooby-gson/src/main/java/org/jooby/json/GsonParser.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,16 @@ public GsonParser(final MediaType type, final Gson gson) {
3939

4040
@Override
4141
public Object parse(final TypeLiteral<?> type, final Context ctx) throws Exception {
42-
if (ctx.type().matches(this.type)) {
43-
return ctx.body(body -> gson.fromJson(body.text(), type.getType()));
42+
MediaType ctype = ctx.type();
43+
if (ctype.isAny()) {
44+
// */*
45+
return ctx.next();
46+
}
47+
48+
if (ctype.matches(this.type)) {
49+
return ctx
50+
.body(body -> gson.fromJson(body.text(), type.getType()))
51+
.param(values -> gson.fromJson(values.first(), type.getType()));
4452
}
4553
return ctx.next();
4654
}

jooby-gson/src/test/java/org/jooby/json/GsonParserTest.java

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public class GsonParserTest {
2121

2222
@SuppressWarnings("unchecked")
2323
@Test
24-
public void parse() throws Exception {
24+
public void parseBody() throws Exception {
2525
TypeLiteral<GsonParserTest> type = TypeLiteral.get(GsonParserTest.class);
2626
Object value = new Object();
2727
new MockUnit(Gson.class, Parser.Context.class, Parser.BodyReference.class)
@@ -32,6 +32,7 @@ public void parse() throws Exception {
3232
Parser.Builder builder = unit.mock(Parser.Builder.class);
3333

3434
expect(ctx.body(unit.capture(Parser.Callback.class))).andReturn(builder);
35+
expect(builder.param(unit.capture(Parser.Callback.class))).andReturn(builder);
3536
})
3637
.expect(unit -> {
3738
Parser.BodyReference ref = unit.get(Parser.BodyReference.class);
@@ -50,6 +51,38 @@ public void parse() throws Exception {
5051
});
5152
}
5253

54+
@SuppressWarnings("unchecked")
55+
@Test
56+
public void parseParam() throws Exception {
57+
TypeLiteral<GsonParserTest> type = TypeLiteral.get(GsonParserTest.class);
58+
Object value = new Object();
59+
new MockUnit(Gson.class, Parser.Context.class, Parser.ParamReference.class)
60+
.expect(unit -> {
61+
Context ctx = unit.get(Parser.Context.class);
62+
expect(ctx.type()).andReturn(MediaType.json);
63+
64+
Parser.Builder builder = unit.mock(Parser.Builder.class);
65+
66+
expect(ctx.body(unit.capture(Parser.Callback.class))).andReturn(builder);
67+
expect(builder.param(unit.capture(Parser.Callback.class))).andReturn(builder);
68+
})
69+
.expect(unit -> {
70+
Parser.ParamReference ref = unit.get(Parser.ParamReference.class);
71+
expect(ref.first()).andReturn("{}");
72+
})
73+
.expect(unit -> {
74+
Gson gson = unit.get(Gson.class);
75+
expect(gson.fromJson("{}", type.getType())).andReturn(value);
76+
})
77+
.run(unit -> {
78+
new GsonParser(MediaType.json, unit.get(Gson.class))
79+
.parse(type, unit.get(Parser.Context.class));
80+
}, unit -> {
81+
unit.captured(Parser.Callback.class).get(1)
82+
.invoke(unit.get(Parser.ParamReference.class));
83+
});
84+
}
85+
5386
@Test
5487
public void next() throws Exception {
5588
TypeLiteral<GsonParserTest> type = TypeLiteral.get(GsonParserTest.class);
@@ -65,6 +98,21 @@ public void next() throws Exception {
6598
});
6699
}
67100

101+
@Test
102+
public void nextAny() throws Exception {
103+
TypeLiteral<GsonParserTest> type = TypeLiteral.get(GsonParserTest.class);
104+
new MockUnit(Gson.class, Parser.Context.class, Parser.BodyReference.class)
105+
.expect(unit -> {
106+
Context ctx = unit.get(Parser.Context.class);
107+
expect(ctx.type()).andReturn(MediaType.all);
108+
expect(ctx.next()).andReturn(null);
109+
})
110+
.run(unit -> {
111+
new GsonParser(MediaType.json, unit.get(Gson.class))
112+
.parse(type, unit.get(Parser.Context.class));
113+
});
114+
}
115+
68116
@Test
69117
public void toStr() throws Exception {
70118
new MockUnit(Gson.class)

jooby-hotreload/src/main/java/org/jooby/hotreload/AppModule.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020

2121
import java.io.BufferedReader;
2222
import java.io.File;
23+
import java.io.FileInputStream;
2324
import java.io.IOException;
25+
import java.io.InputStream;
2426
import java.io.InputStreamReader;
2527
import java.lang.reflect.InvocationTargetException;
2628
import java.nio.file.FileSystems;
@@ -30,6 +32,8 @@
3032
import java.util.ArrayList;
3133
import java.util.Arrays;
3234
import java.util.List;
35+
import java.util.Map.Entry;
36+
import java.util.Properties;
3337
import java.util.concurrent.ExecutorService;
3438
import java.util.concurrent.Executors;
3539

@@ -64,6 +68,7 @@ public AppModule(final String mId, final String mainClass, final String repo, fi
6468

6569
public static void main(final String[] args) throws Exception {
6670
setPkgs();
71+
setSystemProperties(args[2]);
6772
List<File> cp = new ArrayList<File>();
6873
String includes = "**/*.class,**/*.conf,**/*.properties";
6974
String excludes = "";
@@ -105,6 +110,22 @@ public static void main(final String[] args) throws Exception {
105110
launcher.run();
106111
}
107112

113+
private static void setSystemProperties(final String repo) throws IOException {
114+
try (InputStream in = new FileInputStream(new File(repo, "sys.properties"))) {
115+
Properties properties = new Properties();
116+
properties.load(in);
117+
for (Entry<Object, Object> prop : properties.entrySet()) {
118+
String name = prop.getKey().toString();
119+
String value = prop.getValue().toString();
120+
String existing = System.getProperty(name);
121+
if (!value.equals(existing)) {
122+
// set property
123+
System.setProperty(name, value);
124+
}
125+
}
126+
}
127+
}
128+
108129
private static void setPkgs() throws IOException {
109130
BufferedReader stream =
110131
new BufferedReader(new InputStreamReader(AppModule.class.getResourceAsStream("pkgs")));

jooby-jackson/src/main/java/org/jooby/json/JacksonParser.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,16 @@ public JacksonParser(final ObjectMapper mapper, final MediaType type) {
3939

4040
@Override
4141
public Object parse(final TypeLiteral<?> type, final Context ctx) throws Exception {
42+
MediaType ctype = ctx.type();
43+
if (ctype.isAny()) {
44+
// */*
45+
return ctx.next();
46+
}
47+
4248
JavaType javaType = mapper.constructType(type.getType());
43-
if (matcher.matches(ctx.type()) && mapper.canDeserialize(javaType)) {
44-
return ctx.body(body -> mapper.readValue(body.bytes(), javaType));
49+
if (matcher.matches(ctype) && mapper.canDeserialize(javaType)) {
50+
return ctx.body(body -> mapper.readValue(body.bytes(), javaType))
51+
.param(values -> mapper.readValue(values.iterator().next(), javaType));
4552
}
4653
return ctx.next();
4754
}

jooby-maven-plugin/src/main/java/org/jooby/JoobyMojo.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@
1919
package org.jooby;
2020

2121
import java.io.File;
22+
import java.io.FileOutputStream;
23+
import java.io.IOException;
2224
import java.nio.charset.StandardCharsets;
2325
import java.nio.file.Path;
2426
import java.nio.file.Paths;
2527
import java.util.ArrayList;
2628
import java.util.LinkedHashSet;
2729
import java.util.List;
2830
import java.util.Optional;
31+
import java.util.Properties;
2932
import java.util.Set;
3033
import java.util.stream.Collectors;
3134

@@ -95,6 +98,9 @@ public void execute() throws MojoExecutionException, MojoFailureException {
9598

9699
doFlatMainModule(mavenProject, jmodules, appcp, artifacts);
97100

101+
// allow to access command line system properties
102+
dumpSysProps(jmodules.resolve("sys.properties"));
103+
98104
Set<String> classpath = new LinkedHashSet<String>();
99105

100106
String hotreload = extra(pluginArtifacts, "jooby-hotreload").get().getFile().getAbsolutePath();
@@ -150,6 +156,16 @@ public void execute() throws MojoExecutionException, MojoFailureException {
150156

151157
}
152158

159+
private void dumpSysProps(final Path path) throws MojoFailureException {
160+
try {
161+
FileOutputStream output = new FileOutputStream(path.toFile());
162+
Properties properties = System.getProperties();
163+
properties.store(output, "system properties");
164+
} catch (IOException ex) {
165+
throw new MojoFailureException("Can't dump system properties to: " + path, ex);
166+
}
167+
}
168+
153169
/**
154170
* Creates a module.
155171
*
@@ -187,6 +203,7 @@ private void doFlatMainModule(final MavenProject project, final Path jmodules,
187203
.append("\" />\n");
188204
}
189205
}
206+
190207
String content = jbossModule(project.getGroupId(), project.getArtifactId(), rsb, null);
191208
moddir.toFile().mkdirs();
192209
Files.write(content, moddir.resolve("module.xml").toFile(), StandardCharsets.UTF_8);

0 commit comments

Comments
 (0)