Skip to content

Commit 8fdaebd

Browse files
committed
#88 - Helidon Nima support initial
1 parent e5dd22e commit 8fdaebd

File tree

15 files changed

+660
-1
lines changed

15 files changed

+660
-1
lines changed

http-generator-core/src/main/java/io/avaje/http/generator/core/PathSegments.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ private String fullPath(String prefix, String suffix) {
126126
return chunks.fullPath(prefix, suffix);
127127
}
128128

129+
public boolean isEmpty() {
130+
return segments.isEmpty();
131+
}
132+
129133
public static class Segment {
130134

131135
private final String name;

http-generator-nima/pom.xml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>avaje-http-generator-parent</artifactId>
7+
<groupId>io.avaje</groupId>
8+
<version>1.18-SNAPSHOT</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
12+
<artifactId>avaje-http-nima-generator</artifactId>
13+
14+
<properties>
15+
<maven.compiler.source>17</maven.compiler.source>
16+
<maven.compiler.target>17</maven.compiler.target>
17+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
18+
</properties>
19+
20+
<dependencies>
21+
22+
<dependency>
23+
<groupId>io.avaje</groupId>
24+
<artifactId>avaje-http-generator-core</artifactId>
25+
<version>${project.version}</version>
26+
</dependency>
27+
28+
</dependencies>
29+
30+
<build>
31+
<plugins>
32+
<plugin>
33+
<groupId>org.apache.maven.plugins</groupId>
34+
<artifactId>maven-compiler-plugin</artifactId>
35+
<version>3.10.1</version>
36+
<configuration>
37+
<source>11</source>
38+
<target>11</target>
39+
<!-- Turn off annotation processing for building -->
40+
<compilerArgument>-proc:none</compilerArgument>
41+
</configuration>
42+
</plugin>
43+
</plugins>
44+
</build>
45+
46+
</project>
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package io.avaje.http.generator.helidon.nima;
2+
3+
import io.avaje.http.api.MediaType;
4+
import io.avaje.http.generator.core.*;
5+
6+
import java.util.List;
7+
8+
/**
9+
* Write code to register Web route for a given controller method.
10+
*/
11+
class ControllerMethodWriter {
12+
13+
private final MethodReader method;
14+
private final Append writer;
15+
private final WebMethod webMethod;
16+
private final ProcessingContext ctx;
17+
18+
ControllerMethodWriter(MethodReader method, Append writer, ProcessingContext ctx) {
19+
this.method = method;
20+
this.writer = writer;
21+
this.webMethod = method.getWebMethod();
22+
this.ctx = ctx;
23+
}
24+
25+
void writeRule() {
26+
final String fullPath = method.getFullPath();
27+
// final String bodyType = method.getBodyType();
28+
// if (bodyType != null) {
29+
// writer.append(" rules.%s(\"%s\", Handler.create(%s.class, this::_%s));", webMethod.name().toLowerCase(), fullPath, bodyType, method.simpleName()).eol();
30+
// } else if (method.isFormBody()) {
31+
// writer.append(" rules.%s(\"%s\", Handler.create(%s.class, this::_%s));", webMethod.name().toLowerCase(), fullPath, "FormParams", method.simpleName()).eol();
32+
// } else {
33+
writer.append(" rules.%s(\"%s\", this::_%s);", webMethod.name().toLowerCase(), fullPath, method.simpleName()).eol();
34+
// }
35+
}
36+
37+
void writeHandler(boolean requestScoped) {
38+
writer.append(" private void _%s(ServerRequest req, ServerResponse res", method.simpleName());
39+
40+
writer.append(") {").eol();
41+
// if (!method.isVoid()) {
42+
// writeContextReturn();
43+
// }
44+
45+
final String bodyType = method.getBodyType();
46+
if (bodyType != null) {
47+
writer.append(" // body - %s %s", bodyType, method.getBodyName()).eol();
48+
}// else if (method.isFormBody()) {
49+
// writer.append(", %s %s", "FormParams", "formParams");
50+
//}
51+
52+
final PathSegments segments = method.getPathSegments();
53+
if (!segments.isEmpty()) {
54+
writer.append(" var pathParams = req.path().pathParameters();").eol();
55+
56+
}
57+
List<PathSegments.Segment> matrixSegments = segments.matrixSegments();
58+
for (PathSegments.Segment matrixSegment : matrixSegments) {
59+
matrixSegment.writeCreateSegment(writer, ctx.platform());
60+
}
61+
62+
final List<MethodParam> params = method.getParams();
63+
for (MethodParam param : params) {
64+
param.writeCtxGet(writer, segments);
65+
}
66+
writer.append(" ");
67+
if (!method.isVoid()) {
68+
writer.append("var result = ");
69+
//writer.append("res.send(");
70+
}
71+
72+
if (method.includeValidate()) {
73+
for (MethodParam param : params) {
74+
param.writeValidate(writer);
75+
}
76+
}
77+
if (requestScoped) {
78+
writer.append("factory.create(req, res).");
79+
} else {
80+
writer.append("controller.");
81+
}
82+
writer.append(method.simpleName()).append("(");
83+
for (int i = 0; i < params.size(); i++) {
84+
if (i > 0) {
85+
writer.append(", ");
86+
}
87+
params.get(i).buildParamName(writer);
88+
}
89+
writer.append(");").eol();
90+
if (!method.isVoid()) {
91+
writeContextReturn();
92+
writer.append(" res.send(result);").eol();
93+
}
94+
writer.append(" }").eol().eol();
95+
}
96+
97+
private void writeContextReturn() {
98+
final String produces = method.getProduces();
99+
if (produces == null) {
100+
// let it be automatically set
101+
} else if (MediaType.APPLICATION_JSON.equalsIgnoreCase(produces)) {
102+
writer.append(" res.writerContext().contentType(io.helidon.common.http.MediaType.APPLICATION_JSON);").eol();
103+
} else if (MediaType.TEXT_HTML.equalsIgnoreCase(produces)) {
104+
writer.append(" res.writerContext().contentType(io.helidon.common.http.MediaType.TEXT_HTML);").eol();
105+
} else if (MediaType.TEXT_PLAIN.equalsIgnoreCase(produces)) {
106+
writer.append(" res.writerContext().contentType(io.helidon.common.http.MediaType.TEXT_PLAIN);").eol();
107+
} else {
108+
writer.append( "res.writerContext().contentType(io.helidon.common.http.MediaType.parse(\"%s\"));", produces).eol();
109+
}
110+
}
111+
112+
public void buildApiDocumentation() {
113+
method.buildApiDoc();
114+
}
115+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package io.avaje.http.generator.helidon.nima;
2+
3+
import io.avaje.http.generator.core.*;
4+
5+
import java.io.IOException;
6+
import java.util.List;
7+
import java.util.stream.Collectors;
8+
9+
/**
10+
* Write Helidon specific web route adapter (a Helidon Service).
11+
*/
12+
class ControllerWriter extends BaseControllerWriter {
13+
14+
private static final String AT_GENERATED = "@Generated(\"avaje-helidon-nima-generator\")";
15+
16+
ControllerWriter(ControllerReader reader, ProcessingContext ctx) throws IOException {
17+
super(reader, ctx);
18+
//reader.addImportType("io.helidon.common.http.FormParams");
19+
reader.addImportType("io.helidon.nima.webserver.http.HttpRules");
20+
reader.addImportType("io.helidon.nima.webserver.http.HttpRouting");
21+
reader.addImportType("io.helidon.nima.webserver.http.ServerRequest");
22+
reader.addImportType("io.helidon.nima.webserver.http.ServerResponse");
23+
//reader.addImportType("io.helidon.nima.webserver.Routing");
24+
//reader.addImportType("java.util.function.Supplier");
25+
reader.addImportType("io.helidon.nima.webserver.http.HttpService");
26+
}
27+
28+
void write() {
29+
writePackage();
30+
writeImports();
31+
writeClassStart();
32+
writeAddRoutes();
33+
writeClassEnd();
34+
}
35+
36+
private List<ControllerMethodWriter> getWriterMethods() {
37+
return reader.getMethods().stream()
38+
.filter(MethodReader::isWebMethod)
39+
.map(it -> new ControllerMethodWriter(it, writer, ctx))
40+
.collect(Collectors.toList());
41+
}
42+
43+
private void writeAddRoutes() {
44+
final List<ControllerMethodWriter> methods = getWriterMethods();
45+
writeRoutes(methods);
46+
for (ControllerMethodWriter methodWriter : methods) {
47+
methodWriter.writeHandler(isRequestScoped());
48+
}
49+
}
50+
51+
private void writeRoutes(List<ControllerMethodWriter> methods) {
52+
writer.append(" @Override").eol();
53+
writer.append(" public void routing(HttpRules rules) {").eol();
54+
//writer.append(" var rules = HttpRouting.builder();").eol();
55+
for (ControllerMethodWriter methodWriter : methods) {
56+
methodWriter.writeRule();
57+
if (!reader.isDocHidden()) {
58+
methodWriter.buildApiDocumentation();
59+
}
60+
}
61+
//writer.append(" return rules.build();").eol().eol();
62+
writer.append(" }").eol().eol();
63+
}
64+
65+
private void writeClassStart() {
66+
writer.append(AT_GENERATED).eol();
67+
writer.append("@Component").eol();
68+
writer.append("public class ").append(shortName).append("$Route implements HttpService {").eol().eol();
69+
70+
String controllerName = "controller";
71+
String controllerType = shortName;
72+
if (isRequestScoped()) {
73+
controllerName = "factory";
74+
controllerType += Constants.FACTORY_SUFFIX;
75+
}
76+
writer.append(" private final %s %s;", controllerType, controllerName).eol();
77+
if (reader.isIncludeValidator()) {
78+
writer.append(" private final Validator validator;").eol();
79+
}
80+
writer.eol();
81+
82+
writer.append(" public %s$Route(%s %s", shortName, controllerType, controllerName);
83+
if (reader.isIncludeValidator()) {
84+
writer.append(", Validator validator");
85+
}
86+
writer.append(") {").eol();
87+
writer.append(" this.%s = %s;", controllerName, controllerName).eol();
88+
if (reader.isIncludeValidator()) {
89+
writer.append(" this.validator = validator;").eol();
90+
}
91+
writer.append(" }").eol().eol();
92+
}
93+
94+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package io.avaje.http.generator.helidon.nima;
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 NimaPlatformAdapter implements PlatformAdapter {
11+
12+
static final String NIMA_REQ = "io.helidon.nima.webserver.http.ServerRequest";
13+
static final String NIMA_RES = "io.helidon.nima.webserver.http.ServerResponse";
14+
static final String HELIDON_FORMPARAMS = "io.helidon.common.http.FormParams";
15+
16+
@Override
17+
public boolean isContextType(String rawType) {
18+
return NIMA_REQ.equals(rawType) || NIMA_RES.equals(rawType) || HELIDON_FORMPARAMS.equals(rawType);
19+
}
20+
21+
@Override
22+
public String platformVariable(String rawType) {
23+
if (NIMA_REQ.equals(rawType)) {
24+
return "req";
25+
}
26+
if (NIMA_RES.equals(rawType)) {
27+
return "res";
28+
}
29+
if (HELIDON_FORMPARAMS.equals(rawType)) {
30+
return "formParams";
31+
}
32+
return "unknownVariable for: "+rawType;
33+
}
34+
35+
@Override
36+
public boolean isBodyMethodParam() {
37+
return true;
38+
}
39+
40+
@Override
41+
public String bodyAsClass(String shortType) {
42+
return "body";
43+
}
44+
45+
@Override
46+
public String indent() {
47+
return " ";
48+
}
49+
50+
@Override
51+
public void controllerRoles(List<String> roles, ControllerReader controller) {
52+
addRoleImports(roles, controller);
53+
}
54+
55+
@Override
56+
public void methodRoles(List<String> roles, ControllerReader controller) {
57+
addRoleImports(roles, controller);
58+
}
59+
60+
private void addRoleImports(List<String> roles, ControllerReader controller) {
61+
// nothing here yet
62+
}
63+
64+
@Override
65+
public void writeReadParameter(Append writer, ParamType paramType, String paramName) {
66+
switch (paramType) {
67+
case PATHPARAM:
68+
writer.append("pathParams.first(\"%s\").get()", paramName);
69+
break;
70+
case QUERYPARAM:
71+
writer.append("req.query().first(\"%s\").orElse(null)", paramName);
72+
break;
73+
case FORMPARAM:
74+
writer.append("formParams.first(\"%s\").orElse(null)", paramName);
75+
break;
76+
case HEADER:
77+
writer.append("req.headers().value(Http.Header.create(\"%s\").orElse(null)", paramName);
78+
break;
79+
case COOKIE:
80+
writer.append("req.headers().cookies().first(\"%s\").orElse(null)", paramName);
81+
break;
82+
case BODY:
83+
case BEANPARAM:
84+
case FORM:
85+
default:
86+
writer.append("null // TODO req.%s().param(\"%s\")", paramType.getType(), paramName);
87+
}
88+
}
89+
90+
@Override
91+
public void writeReadParameter(Append writer, ParamType paramType, String paramName, String paramDefault) {
92+
switch (paramType) {
93+
case PATHPARAM:
94+
writer.append("pathParams.first(\"%s\").orElse(\"%s\")", paramName, paramDefault);
95+
break;
96+
case QUERYPARAM:
97+
writer.append("req.query().first(\"%s\").orElse(\"%s\")", paramName, paramDefault);
98+
break;
99+
case FORMPARAM:
100+
writer.append("formParams.first(\"%s\").orElse(\"%s\")", paramName, paramDefault);
101+
break;
102+
case HEADER:
103+
writer.append("req.headers().value(Http.Header.create(\"%s\").orElse(\"%s\")", paramName, paramDefault);
104+
break;
105+
case COOKIE:
106+
writer.append("req.headers().cookies().first(\"%s\").orElse(\"%s\")", paramName, paramDefault);
107+
break;
108+
case BODY:
109+
case BEANPARAM:
110+
case FORM:
111+
default:
112+
writer.append("null // TODO req.%s().param(\"%s\")", paramType.getType(), paramName);
113+
}
114+
}
115+
}

0 commit comments

Comments
 (0)