Skip to content

Commit 87e5d69

Browse files
committed
apitool: add support for use("/path", MvcRoutes.class) fix #947
1 parent d76201d commit 87e5d69

File tree

7 files changed

+136
-28
lines changed

7 files changed

+136
-28
lines changed

modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/BytecodeRouteParser.java

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -502,18 +502,7 @@ private List<Object> lambdas(final ClassLoader loader, final ClassNode owner, Me
502502
result.addAll(pathOperator(owner, owner.methods, it));
503503
})
504504
// use(Mvc class)
505-
.on(use(loader, owner.name), it -> {
506-
log.debug("found mvc: " + it);
507-
it.prev()
508-
.filter(is(LdcInsnNode.class))
509-
.findFirst()
510-
.map(LdcInsnNode.class::cast)
511-
.filter(ldc -> ldc.cst instanceof Type)
512-
.map(ldc -> ((Type) ldc.cst).getClassName())
513-
.ifPresent(mvcClass ->
514-
mvcRoutes((Class) loadType(loader, mvcClass), result::add)
515-
);
516-
})
505+
.on(use(loader, owner.name), it -> mvc(it, result::add))
517506
// use(new App());
518507
.on(mount(loader, owner.name), it -> {
519508
log.debug("found mount: " + it);
@@ -597,13 +586,16 @@ private List<Object> lambdas(final ClassLoader loader, final ClassNode owner) {
597586
}
598587
}
599588

600-
private void mvcRoutes(final Class type, Consumer<RouteMethod> callback) {
589+
private void mvcRoutes(String path, final Class type, Consumer<RouteMethod> callback) {
601590
Env env = Env.DEFAULT.build(ConfigFactory.empty()
602591
.withValue("application.env", ConfigValueFactory.fromAnyRef("dev")));
603592
MvcRoutes.routes(env, new RouteMetadata(env), "", true, type)
604593
.forEach(r -> {
605594
RouteMethod method = toRouteMethod(r);
606595
javadoc(method, javadoc.pop(type.getName(), r.method(), r.pattern()));
596+
if (path.length() >0) {
597+
method.pattern(Route.normalize(path) + method.pattern());
598+
}
607599
callback.accept(method);
608600
});
609601
}
@@ -687,17 +679,7 @@ private List<Object> kotlinLambda(final ClassLoader loader, final ClassNode owne
687679
});
688680
})
689681
// use(Mvc class)
690-
.on(use(loader, "org.jooby.Kooby"), it -> {
691-
it.prev()
692-
.filter(is(LdcInsnNode.class))
693-
.findFirst()
694-
.map(LdcInsnNode.class::cast)
695-
.filter(ldc -> ldc.cst instanceof Type)
696-
.map(ldc -> ((Type) ldc.cst).getClassName())
697-
.ifPresent(mvcClass ->
698-
mvcRoutes((Class) loadType(loader, mvcClass), result::add)
699-
);
700-
})
682+
.on(use(loader, "org.jooby.Kooby"), it -> mvc(it, result::add))
701683
// route ("...") {...}
702684
.on(call(loader, "org.jooby.Kooby", "route", String.class,
703685
"kotlin.jvm.functions.Function1"), it -> {
@@ -748,6 +730,30 @@ private List<Object> kotlinLambda(final ClassLoader loader, final ClassNode owne
748730
return result;
749731
}
750732

733+
private void mvc(Insn<MethodInsnNode> it, Consumer<Object> consumer) {
734+
log.debug("found mvc {}", it);
735+
it.prev()
736+
.filter(is(LdcInsnNode.class))
737+
.findFirst()
738+
.map(LdcInsnNode.class::cast)
739+
.filter(ldc -> ldc.cst instanceof Type)
740+
.ifPresent(ldc -> {
741+
String arg0 = Type.getArgumentTypes(it.node.desc)[0].getClassName();
742+
String prefix = "";
743+
if (arg0.equals(String.class.getName())) {
744+
prefix = new Insn<>(it.method, ldc.getPrevious())
745+
.prev()
746+
.filter(is(LdcInsnNode.class))
747+
.findFirst()
748+
.map(LdcInsnNode.class::cast)
749+
.map(n -> n.cst.toString())
750+
.orElse("");
751+
}
752+
String mvcClass = ((Type) ldc.cst).getClassName();
753+
mvcRoutes(prefix, (Class) loadType(loader, mvcClass), consumer::accept);
754+
});
755+
}
756+
751757
private List<Object> kotlinLambda(final ClassLoader loader, final ClassNode owner) {
752758
List<Object> result = new ArrayList<>();
753759
log.debug("visiting lambda class: {}", owner.name);
@@ -1200,7 +1206,8 @@ private static class TypeWithStatus implements java.lang.reflect.Type {
12001206
}
12011207

12021208
public java.lang.reflect.Type type() {
1203-
if (status != null && status == 204 && forwarding.getTypeName().equals(Result.class.getName())) {
1209+
if (status != null && status == 204 && forwarding.getTypeName()
1210+
.equals(Result.class.getName())) {
12041211
return void.class;
12051212
}
12061213
return forwarding;

modules/jooby-apitool/src/main/java/org/jooby/internal/apitool/Filters.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,8 @@ public static Predicate<MethodInsnNode> call(final Class owner, final String nam
263263
}
264264

265265
@SuppressWarnings("rawtypes")
266-
public static Predicate<MethodInsnNode> call(final ClassLoader loader,final String owner, final String name,
266+
public static Predicate<MethodInsnNode> call(final ClassLoader loader, final String owner,
267+
final String name,
267268
final Object... args) {
268269
return is(MethodInsnNode.class).and(m -> {
269270
return new Signature(loader, owner, name, args).matches(m);
@@ -294,11 +295,14 @@ public static Predicate<MethodInsnNode> mount(final ClassLoader loader, final St
294295

295296
public static Predicate<MethodInsnNode> use(final ClassLoader loader, final String owner) {
296297
Signature use = new Signature(loader, owner, "use", Class.class);
298+
Signature usepath = new Signature(loader, owner, "use", String.class, Class.class);
297299
Signature kuse = new Signature(loader, owner, "use", "kotlin.reflect.KClass");
298-
return is(MethodInsnNode.class).and(m -> use.matches(m) || kuse.matches(m));
300+
Signature kusepath = new Signature(loader, owner, "use", String.class, "kotlin.reflect.KClass");
301+
return is(MethodInsnNode.class)
302+
.and(m -> use.matches(m) || usepath.matches(m) || kuse.matches(m) || kusepath.matches(m));
299303
}
300304

301-
public static Predicate<MethodInsnNode> path(final ClassLoader loader,final String owner) {
305+
public static Predicate<MethodInsnNode> path(final ClassLoader loader, final String owner) {
302306
Signature path = new Signature(loader, owner, "path", String.class, Runnable.class);
303307
return is(MethodInsnNode.class).and(m -> path.matches(m));
304308
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package apps;
2+
3+
import org.jooby.Jooby;
4+
5+
public class App947 extends Jooby {
6+
{
7+
use("/path", Routes947.class);
8+
}
9+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package apps;
2+
3+
import org.jooby.mvc.Body;
4+
import org.jooby.mvc.Header;
5+
import org.jooby.mvc.POST;
6+
import org.jooby.mvc.Path;
7+
8+
import javax.inject.Named;
9+
10+
/**
11+
* MVC API.
12+
*/
13+
@Path("/mvc")
14+
public class Routes947 {
15+
16+
/**
17+
* MVC doIt.
18+
*
19+
* @param q Query string. Like: <code>q=foo</code>
20+
* @return Sterinv value.
21+
*/
22+
@POST
23+
public String doIt(final String q) {
24+
return "dot";
25+
}
26+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package kt
2+
3+
import apps.Routes947
4+
import org.jooby.Kooby
5+
6+
class Kt947: Kooby( {
7+
use("/kpath", Routes947::class)
8+
})
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package org.jooby.apitool;
2+
3+
import apps.App947;
4+
import org.junit.Test;
5+
6+
import java.nio.file.Path;
7+
import java.nio.file.Paths;
8+
9+
public class Issue947 {
10+
11+
@Test
12+
public void shouldProcessMvcWithPath() throws Exception {
13+
new RouteMethodAssert(new ApiParser(dir()).parseFully(new App947()))
14+
.next(r -> {
15+
r.returnType(String.class);
16+
r.pattern("/path/mvc");
17+
r.description("MVC doIt.");
18+
r.summary("MVC API.");
19+
r.param(p -> {
20+
p.name("q");
21+
p.type(String.class);
22+
p.description("Query string. Like: <code>q=foo</code>");
23+
});
24+
}).done();
25+
}
26+
27+
@Test
28+
public void shouldProcessMvcWithPathFromKotlin() throws Exception {
29+
new RouteMethodAssert(new ApiParser(dir()).parse("kt.Kt947"))
30+
.next(r -> {
31+
r.returnType(String.class);
32+
r.pattern("/kpath/mvc");
33+
r.description("MVC doIt.");
34+
r.summary("MVC API.");
35+
r.param(p -> {
36+
p.name("q");
37+
p.type(String.class);
38+
p.description("Query string. Like: <code>q=foo</code>");
39+
});
40+
}).done();
41+
}
42+
43+
private Path dir() {
44+
Path userdir = Paths.get(System.getProperty("user.dir"));
45+
if (!userdir.toString().endsWith("jooby-apitool")) {
46+
userdir = userdir.resolve("modules").resolve("jooby-apitool");
47+
}
48+
return userdir;
49+
}
50+
}

modules/jooby-lang-kotlin/src/main/kotlin/org/jooby/Jooby.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,10 @@ open class Kooby constructor(): Jooby() {
217217
return use(klass.java)
218218
}
219219

220+
fun <T:Any> use(path: String, klass: KClass<T>): Route.Collection {
221+
return use(path, klass.java)
222+
}
223+
220224
fun <T:Session.Store> session(klass: KClass<T>): Session.Definition {
221225
return session(klass.java)
222226
}

0 commit comments

Comments
 (0)