Skip to content

Commit f3ac04e

Browse files
committed
#46 - Add support for generating controller adapters for Jex
1 parent 37e51ef commit f3ac04e

File tree

16 files changed

+583
-2
lines changed

16 files changed

+583
-2
lines changed

http-generator-jex/pom.xml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<artifactId>avaje-http-jex-generator</artifactId>
6+
7+
<parent>
8+
<groupId>io.avaje</groupId>
9+
<artifactId>avaje-http-generator-parent</artifactId>
10+
<version>1.1-SNAPSHOT</version>
11+
<relativePath>..</relativePath>
12+
</parent>
13+
14+
<dependencies>
15+
16+
<dependency>
17+
<groupId>io.avaje</groupId>
18+
<artifactId>avaje-http-generator-core</artifactId>
19+
<version>${project.version}</version>
20+
</dependency>
21+
22+
</dependencies>
23+
24+
25+
<build>
26+
<plugins>
27+
<plugin>
28+
<groupId>org.apache.maven.plugins</groupId>
29+
<artifactId>maven-compiler-plugin</artifactId>
30+
<version>3.2</version>
31+
<configuration>
32+
<source>1.8</source>
33+
<target>1.8</target>
34+
<!-- Turn off annotation processing for building -->
35+
<compilerArgument>-proc:none</compilerArgument>
36+
</configuration>
37+
</plugin>
38+
</plugins>
39+
</build>
40+
41+
42+
</project>
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package io.avaje.http.generator.jex;
2+
3+
import io.avaje.http.api.MediaType;
4+
import io.avaje.http.generator.core.Append;
5+
import io.avaje.http.generator.core.MethodParam;
6+
import io.avaje.http.generator.core.MethodReader;
7+
import io.avaje.http.generator.core.PathSegments;
8+
import io.avaje.http.generator.core.ProcessingContext;
9+
import io.avaje.http.generator.core.Util;
10+
import io.avaje.http.generator.core.WebMethod;
11+
12+
import java.util.List;
13+
14+
/**
15+
* Write code to register Web route for a given controller method.
16+
*/
17+
class ControllerMethodWriter {
18+
19+
private final MethodReader method;
20+
private final Append writer;
21+
private final WebMethod webMethod;
22+
private final ProcessingContext ctx;
23+
24+
ControllerMethodWriter(MethodReader method, Append writer, ProcessingContext ctx) {
25+
this.method = method;
26+
this.writer = writer;
27+
this.webMethod = method.getWebMethod();
28+
this.ctx = ctx;
29+
}
30+
31+
void write(boolean requestScoped) {
32+
33+
final PathSegments segments = method.getPathSegments();
34+
final String fullPath = segments.fullPathColon();
35+
36+
writer.append(" routing.%s(\"%s\", ctx -> {", webMethod.name().toLowerCase(), fullPath).eol();
37+
writer.append(" ctx.status(%s);", method.getStatusCode()).eol();
38+
39+
List<PathSegments.Segment> matrixSegments = segments.matrixSegments();
40+
for (PathSegments.Segment matrixSegment : matrixSegments) {
41+
matrixSegment.writeCreateSegment(writer, ctx.platform());
42+
}
43+
44+
final List<MethodParam> params = method.getParams();
45+
for (MethodParam param : params) {
46+
param.writeCtxGet(writer, segments);
47+
}
48+
writer.append(" ");
49+
if (method.includeValidate()) {
50+
for (MethodParam param : params) {
51+
param.writeValidate(writer);
52+
}
53+
}
54+
if (!method.isVoid()) {
55+
writeContextReturn();
56+
}
57+
58+
if (requestScoped) {
59+
writer.append("factory.create(ctx).");
60+
} else {
61+
writer.append("controller.");
62+
}
63+
writer.append(method.simpleName()).append("(");
64+
for (int i = 0; i < params.size(); i++) {
65+
if (i > 0) {
66+
writer.append(", ");
67+
}
68+
params.get(i).buildParamName(writer);
69+
}
70+
writer.append(")");
71+
if (!method.isVoid()) {
72+
writer.append(")");
73+
}
74+
writer.append(";").eol();
75+
writer.append(" }");
76+
77+
List<String> roles = method.roles();
78+
if (!roles.isEmpty()) {
79+
writer.append(", roles(");
80+
for (int i = 0; i < roles.size(); i++) {
81+
if (i > 0) {
82+
writer.append(", ");
83+
}
84+
writer.append(Util.shortName(roles.get(i)));
85+
}
86+
writer.append(")");
87+
}
88+
writer.append(");").eol().eol();
89+
}
90+
91+
private void writeContextReturn() {
92+
final String produces = method.getProduces();
93+
if (produces == null || produces.equalsIgnoreCase(MediaType.APPLICATION_JSON)) {
94+
writer.append("ctx.json(");
95+
} else if (produces.equalsIgnoreCase(MediaType.TEXT_HTML)) {
96+
writer.append("ctx.html(");
97+
} else if (produces.equalsIgnoreCase(MediaType.TEXT_PLAIN)) {
98+
writer.append("ctx.contentType(\"text/plain\").result(");
99+
} else {
100+
writer.append("ctx.contentType(\"%s\").result(", produces);
101+
}
102+
}
103+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package io.avaje.http.generator.jex;
2+
3+
import io.avaje.http.generator.core.BaseControllerWriter;
4+
import io.avaje.http.generator.core.ControllerReader;
5+
import io.avaje.http.generator.core.MethodReader;
6+
import io.avaje.http.generator.core.ProcessingContext;
7+
8+
import java.io.IOException;
9+
10+
/**
11+
* Write Javalin specific Controller WebRoute handling adapter.
12+
*/
13+
class ControllerWriter extends BaseControllerWriter {
14+
15+
private static final String AT_GENERATED = "@Generated(\"avaje-jex-generator\")";
16+
private static final String API_ROUTING = "io.avaje.jex.Routing";
17+
private static final String API_ROUTING_SERVICE = "io.avaje.jex.Routing.Service";
18+
19+
ControllerWriter(ControllerReader reader, ProcessingContext ctx) throws IOException {
20+
super(reader, ctx);
21+
reader.addImportType(API_ROUTING);
22+
reader.addImportType(API_ROUTING_SERVICE);
23+
}
24+
25+
void write() {
26+
writePackage();
27+
writeImports();
28+
writeClassStart();
29+
writeAddRoutes();
30+
writeClassEnd();
31+
}
32+
33+
private void writeAddRoutes() {
34+
writer.append(" @Override").eol();
35+
writer.append(" public void add(Routing routing) {").eol().eol();
36+
for (MethodReader method : reader.getMethods()) {
37+
if (method.isWebMethod()) {
38+
writeForMethod(method);
39+
}
40+
}
41+
writer.append(" }").eol().eol();
42+
}
43+
44+
private void writeForMethod(MethodReader method) {
45+
new ControllerMethodWriter(method, writer, ctx).write(isRequestScoped());
46+
if (!reader.isDocHidden()) {
47+
method.buildApiDocumentation(ctx);
48+
}
49+
}
50+
51+
private void writeClassStart() {
52+
if (ctx.isGeneratedAvailable()) {
53+
writer.append(AT_GENERATED).eol();
54+
}
55+
writer.append("@Singleton").eol();
56+
writer.append("public class ").append(shortName).append("$route implements Routing.Service {").eol().eol();
57+
58+
String controllerName = "controller";
59+
String controllerType = shortName;
60+
if (isRequestScoped()) {
61+
controllerName = "factory";
62+
controllerType += "$factory";
63+
}
64+
writer.append(" private final %s %s;", controllerType, controllerName).eol();
65+
66+
if (reader.isIncludeValidator()) {
67+
writer.append(" private final Validator validator;").eol();
68+
}
69+
writer.eol();
70+
71+
writer.append(" public %s$route(%s %s", shortName, controllerType, controllerName);
72+
if (reader.isIncludeValidator()) {
73+
writer.append(", Validator validator");
74+
}
75+
writer.append(") {").eol();
76+
writer.append(" this.%s = %s;", controllerName, controllerName).eol();
77+
if (reader.isIncludeValidator()) {
78+
writer.append(" this.validator = validator;").eol();
79+
}
80+
writer.append(" }").eol().eol();
81+
}
82+
83+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package io.avaje.http.generator.jex;
2+
3+
import io.avaje.http.generator.core.Append;
4+
import io.avaje.http.generator.core.ControllerReader;
5+
import io.avaje.http.generator.core.ParamType;
6+
import io.avaje.http.generator.core.PlatformAdapter;
7+
8+
import java.util.List;
9+
10+
class JexAdapter implements PlatformAdapter {
11+
12+
static final String JEX_CONTEXT = "io.avaje.jex.Context";
13+
//static final String JAVALIN3_ROLES = "io.javalin.core.security.SecurityUtil.roles";
14+
15+
@Override
16+
public boolean isContextType(String rawType) {
17+
return JEX_CONTEXT.equals(rawType);
18+
}
19+
20+
@Override
21+
public String platformVariable(String rawType) {
22+
return "ctx";
23+
}
24+
25+
@Override
26+
public boolean isBodyMethodParam() {
27+
return false;
28+
}
29+
30+
@Override
31+
public String bodyAsClass(String shortType) {
32+
return "ctx.bodyAsClass(" + shortType + ".class)";
33+
}
34+
35+
@Override
36+
public String indent() {
37+
return " ";
38+
}
39+
40+
@Override
41+
public void controllerRoles(List<String> roles, ControllerReader controller) {
42+
//addRoleImports(roles, controller);
43+
}
44+
45+
@Override
46+
public void methodRoles(List<String> roles, ControllerReader controller) {
47+
//addRoleImports(roles, controller);
48+
}
49+
50+
// private void addRoleImports(List<String> roles, ControllerReader controller) {
51+
// controller.addStaticImportType(JAVALIN3_ROLES);
52+
// for (String role : roles) {
53+
// controller.addStaticImportType(role);
54+
// }
55+
// }
56+
57+
@Override
58+
public void writeReadParameter(Append writer, ParamType paramType, String paramName) {
59+
writer.append("ctx.%s(\"%s\")", paramType, paramName);
60+
}
61+
62+
@Override
63+
public void writeReadParameter(Append writer, ParamType paramType, String paramName, String paramDefault) {
64+
writer.append("ctx.%s(\"%s\",\"%s\")", paramType, paramName, paramDefault);
65+
}
66+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package io.avaje.http.generator.jex;
2+
3+
import io.avaje.http.generator.core.BaseProcessor;
4+
import io.avaje.http.generator.core.ControllerReader;
5+
import io.avaje.http.generator.core.PlatformAdapter;
6+
import io.avaje.http.generator.core.ProcessingContext;
7+
8+
import java.io.IOException;
9+
10+
public class JexProcessor extends BaseProcessor {
11+
12+
@Override
13+
protected PlatformAdapter providePlatformAdapter() {
14+
return new JexAdapter();
15+
}
16+
17+
@Override
18+
public void writeControllerAdapter(ProcessingContext ctx, ControllerReader reader) throws IOException {
19+
new ControllerWriter(reader, ctx).write();
20+
}
21+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
io.avaje.http.generator.jex.JexProcessor

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
<!-- <module>http-api</module>-->
3333
<module>http-generator-core</module>
3434
<module>http-generator-javalin</module>
35+
<module>http-generator-jex</module>
3536
<module>http-generator-helidon</module>
3637
<module>http-generator-spark</module>
3738
<!-- <module>http-generator-client</module>-->

tests/pom.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
<modules>
1313
<module>test-helidon</module>
1414
<module>test-javalin</module>
15-
<!-- <module>test-spark</module>-->
15+
<module>test-jex</module>
16+
<!-- <module>test-spark</module>-->
1617
<module>test-client</module>
1718
</modules>
1819

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ HelloDto hello(int id, LocalDate date, String otherParam) {
6767
* @param myParam My option parameter
6868
* @return The Hellos that we found.
6969
*/
70-
@Get("/findbyname/:name")
70+
@Get("/findbyname/{name}")
7171
List<HelloDto> findByName(String name, @QueryParam("my-param") @Default("one") String myParam) {
7272
return new ArrayList<>();
7373
}

0 commit comments

Comments
 (0)