Skip to content

Commit ec588aa

Browse files
committed
Flash annotations for MVC routes
1 parent 74239b7 commit ec588aa

File tree

7 files changed

+123
-16
lines changed

7 files changed

+123
-16
lines changed

docs/asciidoc/mvc-api.adoc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,37 @@ class MyController {
295295
}
296296
----
297297

298+
==== Flash
299+
300+
Provisioning of flash attribute is available via javadoc:annotations.FlashParam[] annotation:
301+
302+
.Flash
303+
[source, java, role = "primary"]
304+
----
305+
public class MyController {
306+
307+
@GET
308+
public Object provisioning(@FlashParam String success) { // <1>
309+
...
310+
}
311+
}
312+
----
313+
314+
.Kotlin
315+
[source, kotlin, role = "secondary"]
316+
----
317+
class MyController {
318+
319+
@GET
320+
fun provisioning(@FlashParam success: String) : Any { // <1>
321+
...
322+
}
323+
}
324+
----
325+
326+
<1> Access to flash named `success`
327+
328+
298329
=== Registration
299330

300331
Mvc routes need to be registered (no classpath scanning). Registration is done from your application
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package io.jooby.annotations;
7+
8+
import java.lang.annotation.ElementType;
9+
import java.lang.annotation.Retention;
10+
import java.lang.annotation.RetentionPolicy;
11+
import java.lang.annotation.Target;
12+
13+
/**
14+
* Allow access to flash parameter from MVC route method.
15+
*
16+
* <pre>{@code
17+
* public String search(&#64;FlashParam String q) {
18+
* ...
19+
* }
20+
* }</pre>
21+
*/
22+
@Retention(RetentionPolicy.RUNTIME)
23+
@Target(ElementType.PARAMETER)
24+
public @interface FlashParam {
25+
/**
26+
* Parameter name.
27+
*
28+
* @return Parameter name.
29+
*/
30+
String value() default "";
31+
}

jooby/src/main/java/io/jooby/internal/mvc/JoobyAnnotationParser.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import io.jooby.Sneaky;
99
import io.jooby.annotations.CookieParam;
1010
import io.jooby.annotations.DELETE;
11+
import io.jooby.annotations.FlashParam;
1112
import io.jooby.annotations.FormParam;
1213
import io.jooby.annotations.GET;
1314
import io.jooby.annotations.HEAD;
@@ -51,6 +52,7 @@ public class JoobyAnnotationParser extends MvcAnnotationParserBase {
5152
result.setPathParam(PathParam.class);
5253
result.setQueryParam(QueryParam.class);
5354
result.setFormParam(FormParam.class);
55+
result.setFlashParam(FlashParam.class);
5456
return result;
5557
}
5658

jooby/src/main/java/io/jooby/internal/mvc/MvcAnnotation.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ public class MvcAnnotation {
3434

3535
private Class<? extends Annotation> formParam;
3636

37+
private Class<? extends Annotation> flashParam;
38+
3739
public MvcAnnotation(String method, String[] path, String[] produces, String[] consumes) {
3840
this.method = method;
3941
this.path = path;
@@ -86,6 +88,10 @@ public boolean isFormParam(Parameter parameter) {
8688
return parameter.getAnnotation(formParam) != null;
8789
}
8890

91+
public boolean isFlashParam(Parameter parameter) {
92+
return flashParam != null && parameter.getAnnotation(flashParam) != null;
93+
}
94+
8995
public void setHeaderParam(Class<? extends Annotation> headerParam) {
9096
this.headerParam = headerParam;
9197
}
@@ -102,6 +108,10 @@ public void setQueryParam(Class<? extends Annotation> queryParam) {
102108
this.queryParam = queryParam;
103109
}
104110

111+
public void setFlashParam(Class<? extends Annotation> flashParam) {
112+
this.flashParam = flashParam;
113+
}
114+
105115
public void setFormParam(Class<? extends Annotation> formParam) {
106116
this.formParam = formParam;
107117
}

jooby/src/main/java/io/jooby/internal/mvc/MvcCompiler.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package io.jooby.internal.mvc;
77

88
import io.jooby.Context;
9+
import io.jooby.FlashMap;
910
import io.jooby.Formdata;
1011
import io.jooby.Multipart;
1112
import io.jooby.ProvisioningException;
@@ -124,7 +125,8 @@ public class MvcCompiler {
124125
Context.class,
125126
QueryString.class,
126127
Formdata.class,
127-
Multipart.class
128+
Multipart.class,
129+
FlashMap.class
128130
));
129131

130132
public static Class<? extends MvcHandler> compileClass(MvcMethod method)
@@ -438,6 +440,10 @@ private static void tryParamBlock(MvcMethod method, MethodVisitor visitor, Param
438440
visitor
439441
.visitMethodInsn(INVOKEINTERFACE, CTX_INTERNAL, "multipart", "()Lio/jooby/Multipart;",
440442
true);
443+
} else if (paramClass == FlashMap.class) {
444+
visitor
445+
.visitMethodInsn(INVOKEINTERFACE, CTX_INTERNAL, "flashMap", "()Lio/jooby/FlashMap;",
446+
true);
441447
} else {
442448
String source;
443449
String convert;
@@ -495,6 +501,9 @@ private static String httpType(MvcAnnotation model, Parameter parameter, String
495501
} else if (model.isCookieParam(parameter)) {
496502
consumer.accept(paramName(model, parameter, name), "cookie");
497503
return "cookie";
504+
} else if (model.isFlashParam(parameter)) {
505+
consumer.accept(paramName(model, parameter, name), "flash");
506+
return "flash";
498507
}
499508

500509
return null;

tests/src/test/java/examples/Provisioning.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package examples;
22

33
import io.jooby.Context;
4+
import io.jooby.FlashMap;
45
import io.jooby.Formdata;
56
import io.jooby.Multipart;
67
import io.jooby.QueryString;
78
import io.jooby.StatusCode;
89
import io.jooby.annotations.CookieParam;
10+
import io.jooby.annotations.FlashParam;
911
import io.jooby.annotations.FormParam;
1012
import io.jooby.annotations.GET;
1113
import io.jooby.annotations.HeaderParam;
@@ -27,6 +29,12 @@ public String getIt(Context ctx) {
2729
return ctx.pathString();
2830
}
2931

32+
@GET
33+
@Path("/flash")
34+
public String flash(@FlashParam String success, FlashMap flash) {
35+
return flash + success;
36+
}
37+
3038
@GET
3139
@Path("/sendStatusCode")
3240
public Context sendStatusCode(Context ctx) {

tests/src/test/java/io/jooby/MvcTest.java

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ public void provisioning() {
164164
assertEquals("/args/ctx", rsp.body().string());
165165
});
166166

167+
client.header("Cookie", "jooby.flash=success=OK").get("/args/flash", rsp -> {
168+
assertEquals("{success=OK}OK", rsp.body().string());
169+
});
170+
167171
client.get("/args/sendStatusCode", rsp -> {
168172
assertEquals("", rsp.body().string());
169173
assertEquals(201, rsp.code());
@@ -249,8 +253,8 @@ public void provisioning() {
249253

250254
client.header("Cookie", "foo=bar");
251255
client.get("/args/cookie", rsp -> {
252-
assertEquals("bar", rsp.body().string());
253-
});
256+
assertEquals("bar", rsp.body().string());
257+
});
254258
});
255259
}
256260

@@ -275,15 +279,21 @@ public void nullinjection() {
275279
});
276280

277281
client.get("/nullbean", rsp -> {
278-
assertEquals("Unable to provision parameter: 'foo: int', require by: constructor examples.NullInjection.QParam(int, java.lang.Integer)", rsp.body().string());
282+
assertEquals(
283+
"Unable to provision parameter: 'foo: int', require by: constructor examples.NullInjection.QParam(int, java.lang.Integer)",
284+
rsp.body().string());
279285
});
280286

281287
client.get("/nullbean?foo=foo", rsp -> {
282-
assertEquals("Unable to provision parameter: 'foo: int', require by: constructor examples.NullInjection.QParam(int, java.lang.Integer)", rsp.body().string());
288+
assertEquals(
289+
"Unable to provision parameter: 'foo: int', require by: constructor examples.NullInjection.QParam(int, java.lang.Integer)",
290+
rsp.body().string());
283291
});
284292

285293
client.get("/nullbean?foo=0&baz=baz", rsp -> {
286-
assertEquals("Unable to provision parameter: 'baz: int', require by: method examples.NullInjection.QParam.setBaz(int)", rsp.body().string());
294+
assertEquals(
295+
"Unable to provision parameter: 'baz: int', require by: method examples.NullInjection.QParam.setBaz(int)",
296+
rsp.body().string());
287297
});
288298
});
289299
}
@@ -315,17 +325,22 @@ public void mvcBody() {
315325
assertEquals("Unable to provision parameter: 'body: int'", rsp.body().string());
316326
});
317327
client.header("Content-Type", "application/json");
318-
client.post("/body/json", create(MediaType.get("application/json"), "{\"foo\"= \"bar\"}"), rsp -> {
319-
assertEquals("Unable to provision parameter: 'body: java.util.Map<java.lang.String, java.lang.Object>'", rsp.body().string());
320-
});
328+
client.post("/body/json", create(MediaType.get("application/json"), "{\"foo\"= \"bar\"}"),
329+
rsp -> {
330+
assertEquals(
331+
"Unable to provision parameter: 'body: java.util.Map<java.lang.String, java.lang.Object>'",
332+
rsp.body().string());
333+
});
321334
client.header("Content-Type", "application/json");
322-
client.post("/body/json", create(MediaType.get("application/json"), "{\"foo\": \"bar\"}"), rsp -> {
323-
assertEquals("\"{foo=bar}null\"", rsp.body().string());
324-
});
335+
client.post("/body/json", create(MediaType.get("application/json"), "{\"foo\": \"bar\"}"),
336+
rsp -> {
337+
assertEquals("\"{foo=bar}null\"", rsp.body().string());
338+
});
325339
client.header("Content-Type", "application/json");
326-
client.post("/body/json?type=x", create(MediaType.get("application/json"), "{\"foo\": \"bar\"}"), rsp -> {
327-
assertEquals("\"{foo=bar}x\"", rsp.body().string());
328-
});
340+
client.post("/body/json?type=x",
341+
create(MediaType.get("application/json"), "{\"foo\": \"bar\"}"), rsp -> {
342+
assertEquals("\"{foo=bar}x\"", rsp.body().string());
343+
});
329344
});
330345
}
331346

@@ -349,7 +364,8 @@ public void mvcDispatch() {
349364
});
350365
});
351366

352-
LinkedList<String> names = new LinkedList<>(Arrays.asList("netty", "application I/O", "application-"));
367+
LinkedList<String> names = new LinkedList<>(
368+
Arrays.asList("netty", "application I/O", "application-"));
353369
new JoobyRunner(app -> {
354370
app.executor("single", Executors.newSingleThreadExecutor(r ->
355371
new Thread(r, "single")

0 commit comments

Comments
 (0)