Skip to content

Commit e3e0033

Browse files
authored
Update Jex Generation (#517)
* bring jex generator up to speed * copy over some tests * Update pom.xml * Update JexAdapter.java * Update pom.xml * Update pom.xml * Update pom.xml * Update WebController.java
1 parent b144bfe commit e3e0033

File tree

37 files changed

+1957
-107
lines changed

37 files changed

+1957
-107
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package io.avaje.http.api;
2+
3+
import static java.lang.annotation.ElementType.METHOD;
4+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
5+
6+
import java.lang.annotation.Retention;
7+
import java.lang.annotation.Target;
8+
9+
/**
10+
* Marks a method that handles HTTP OPTIONS requests.
11+
*/
12+
@Target(METHOD)
13+
@Retention(RUNTIME)
14+
@HttpMethod("OPTIONS")
15+
public @interface Options {
16+
17+
/** Specify the path. */
18+
String value() default "";
19+
20+
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ public enum CoreWebMethod implements WebMethod {
66
PUT(200, 204),
77
PATCH(200, 204),
88
DELETE(200, 204),
9+
OPTIONS(200, 204),
910
ERROR(500),
1011
FILTER(0),
1112
OTHER(0, 0);
1213

13-
private int statusCode;
14-
private int voidStatusCode;
14+
private final int statusCode;
15+
private final int voidStatusCode;
1516

1617
CoreWebMethod(int statusCode, int voidStatusCode) {
1718
this.statusCode = statusCode;

http-generator-jex/src/main/java/io/avaje/http/generator/jex/ControllerMethodWriter.java

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package io.avaje.http.generator.jex;
22

3+
import static io.avaje.http.generator.core.ProcessingContext.isAssignable2Interface;
4+
import static io.avaje.http.generator.core.ProcessingContext.logError;
35
import static io.avaje.http.generator.core.ProcessingContext.platform;
6+
7+
import java.io.IOException;
48
import java.util.List;
59

610
import io.avaje.http.generator.core.*;
@@ -15,18 +19,35 @@ class ControllerMethodWriter {
1519
private final Append writer;
1620
private final WebMethod webMethod;
1721
private final boolean instrumentContext;
22+
private final boolean isFilter;
1823

1924
ControllerMethodWriter(MethodReader method, Append writer) {
2025
this.method = method;
2126
this.writer = writer;
2227
this.webMethod = method.webMethod();
2328
this.instrumentContext = method.instrumentContext();
29+
this.isFilter = webMethod == CoreWebMethod.FILTER;
30+
if (isFilter) {
31+
validateMethod();
32+
}
33+
}
34+
35+
private void validateMethod() {
36+
if (method.params().stream().map(MethodParam::shortType).noneMatch("FilterChain"::equals)) {
37+
logError(method.element(), "Filters must contain a FilterChain parameter");
38+
}
2439
}
2540

2641
void writeRouting() {
2742
final PathSegments segments = method.pathSegments();
2843
final String fullPath = segments.fullPath();
29-
writer.append(" routing.%s(\"%s\", this::_%s)", webMethod.name().toLowerCase(), fullPath, method.simpleName());
44+
45+
if (isFilter) {
46+
writer.append(" routing.filter(this::_%s)", method.simpleName());
47+
} else {
48+
writer.append(" routing.%s(\"%s\", this::_%s)", webMethod.name().toLowerCase(), fullPath, method.simpleName());
49+
}
50+
3051
List<String> roles = method.roles();
3152
if (!roles.isEmpty()) {
3253
writer.append(".withRoles(");
@@ -42,7 +63,17 @@ void writeRouting() {
4263
}
4364

4465
void writeHandler(boolean requestScoped) {
45-
writer.append(" private void _%s(Context ctx) {", method.simpleName()).eol();
66+
67+
if (method.isErrorMethod()) {
68+
writer.append(" private void _%s(Context ctx, %s ex)", method.simpleName(), method.exceptionShortName());
69+
} else if (isFilter) {
70+
writer.append(" private void _%s(Context ctx, FilterChain chain)", method.simpleName());
71+
} else {
72+
writer.append(" private void _%s(Context ctx)", method.simpleName());
73+
}
74+
75+
writer.append(" throws IOException {", method.simpleName()).eol();
76+
4677
write(requestScoped);
4778
writer.append(" }").eol().eol();
4879
}
@@ -61,7 +92,9 @@ private void write(boolean requestScoped) {
6192

6293
final List<MethodParam> params = method.params();
6394
for (MethodParam param : params) {
64-
param.writeCtxGet(writer, segments);
95+
if (!isExceptionOrFilterChain(param)) {
96+
param.writeCtxGet(writer, segments);
97+
}
6598
}
6699
if (method.includeValidate()) {
67100
for (MethodParam param : params) {
@@ -85,7 +118,14 @@ private void write(boolean requestScoped) {
85118
if (i > 0) {
86119
writer.append(", ");
87120
}
88-
params.get(i).buildParamName(writer);
121+
final var param = params.get(i);
122+
if (isAssignable2Interface(param.utype().mainType(), "java.lang.Exception")) {
123+
writer.append("ex");
124+
} else if ("FilterChain".equals(param.shortType())) {
125+
writer.append("chain");
126+
} else {
127+
param.buildParamName(writer);
128+
}
89129
}
90130
writer.append(")");
91131
if (!method.isVoid()) {
@@ -111,4 +151,9 @@ private void writeContextReturn() {
111151
writer.append("ctx.contentType(\"%s\").write(", produces);
112152
}
113153
}
154+
155+
private static boolean isExceptionOrFilterChain(MethodParam param) {
156+
return isAssignable2Interface(param.utype().mainType(), "java.lang.Exception")
157+
|| "FilterChain".equals(param.shortType());
158+
}
114159
}

http-generator-jex/src/main/java/io/avaje/http/generator/jex/ControllerWriter.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,18 @@ class ControllerWriter extends BaseControllerWriter {
1313
private static final String AT_GENERATED = "@Generated(\"avaje-jex-generator\")";
1414
private static final String API_CONTEXT = "io.avaje.jex.Context";
1515
private static final String API_ROUTING = "io.avaje.jex.Routing";
16-
private static final String API_ROUTING_SERVICE = "io.avaje.jex.Routing.Service";
1716

1817
ControllerWriter(ControllerReader reader) throws IOException {
1918
super(reader);
2019
reader.addImportType(API_CONTEXT);
2120
reader.addImportType(API_ROUTING);
22-
reader.addImportType(API_ROUTING_SERVICE);
21+
reader.addImportType("java.io.IOException");
22+
23+
if (reader.methods().stream()
24+
.map(MethodReader::webMethod)
25+
.anyMatch(w -> CoreWebMethod.FILTER == w)) {
26+
reader.addImportType("io.avaje.jex.FilterChain");
27+
}
2328
}
2429

2530
void write() {
@@ -60,7 +65,7 @@ private void writeRouting(MethodReader method) {
6065
private void writeClassStart() {
6166
writer.append(AT_GENERATED).eol();
6267
writer.append(diAnnotation()).eol();
63-
writer.append("public class ").append(shortName).append("$Route implements Routing.Service {").eol().eol();
68+
writer.append("public class ").append(shortName).append("$Route implements Routing.HttpService {").eol().eol();
6469

6570
String controllerName = "controller";
6671
String controllerType = shortName;

http-generator-jex/src/main/java/io/avaje/http/generator/jex/JexAdapter.java

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,17 @@ public boolean isBodyMethodParam() {
2929
}
3030

3131
@Override
32-
public String bodyAsClass(UType uType) {
33-
if ("java.lang.String".equals(uType.full())) {
32+
public String bodyAsClass(UType type) {
33+
34+
if ("java.io.InputStream".equals(type.full())) {
35+
return "ctx.bodyInputStream()";
36+
} else if ("java.lang.String".equals(type.full())) {
3437
return "ctx.body()";
38+
} else if ("byte[]".equals(type.full())) {
39+
return "ctx.bodyAsBytes()";
3540
}
36-
return "ctx.bodyAsClass(" + uType.mainType() + ".class)";
41+
42+
return "ctx.bodyAsClass(" + type.mainType() + ".class)";
3743
}
3844

3945
@Override
@@ -67,27 +73,62 @@ public void writeReadParameter(Append writer, ParamType paramType, String paramN
6773
writer.append("withDefault(ctx.%s(\"%s\"), \"%s\")", paramType, paramName, paramDefault);
6874
}
6975

76+
@Override
77+
public void writeReadMapParameter(Append writer, ParamType paramType) {
78+
79+
switch (paramType) {
80+
case QUERYPARAM:
81+
writer.append("ctx.queryParamMap()");
82+
break;
83+
case FORM:
84+
case FORMPARAM:
85+
writer.append("ctx.formParamMap()");
86+
break;
87+
default:
88+
throw new UnsupportedOperationException(
89+
"Only Query/Form Params have Map<String, List<String>> supported in Jex");
90+
}
91+
}
92+
7093
@Override
7194
public void writeReadCollectionParameter(Append writer, ParamType paramType, String paramName) {
72-
if (paramType != ParamType.QUERYPARAM) {
73-
throw new UnsupportedOperationException(
74-
"Only MultiValue Query Params are supported in Jex");
95+
switch (paramType) {
96+
case QUERYPARAM:
97+
writer.append("ctx.queryParams(\"%s\")", paramName);
98+
break;
99+
case FORMPARAM:
100+
writer.append("ctx.formParams(\"%s\")", paramName);
101+
break;
102+
default:
103+
throw new UnsupportedOperationException(
104+
"Only MultiValue Form/Query Params are supported in Jex");
75105
}
76-
writer.append("ctx.queryParams(\"%s\")", paramName);
77106
}
78107

79108
@Override
80109
public void writeReadCollectionParameter(
81110
Append writer, ParamType paramType, String paramName, List<String> paramDefault) {
82-
if (paramType != ParamType.QUERYPARAM) {
83-
throw new UnsupportedOperationException(
84-
"Only MultiValue Query Params are supported in Jex");
111+
112+
switch (paramType) {
113+
case QUERYPARAM:
114+
writer.append(
115+
"withDefault(ctx.queryParams(\"%s\"), java.util.List.of(\"%s\"))",
116+
paramName, String.join(",", paramDefault));
117+
break;
118+
case FORMPARAM:
119+
writer.append(
120+
"withDefault(ctx.formParams(\"%s\"), java.util.List.of(\"%s\"))",
121+
paramName, String.join(",", paramDefault));
122+
break;
123+
default:
124+
throw new UnsupportedOperationException(
125+
"Only MultiValue Form/Query Params are supported in Jex");
85126
}
86-
writer.append("withDefault(ctx.queryParams(\"%s\"), java.util.List.of(\"%s\"))", paramName, String.join(",", paramDefault));
87127
}
88128

89129
@Override
90130
public void writeAcceptLanguage(Append writer) {
91131
writer.append("ctx.header(\"%s\")", Constants.ACCEPT_LANGUAGE);
92132
}
133+
93134
}

pom.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
<nexus.staging.autoReleaseAfterClose>true</nexus.staging.autoReleaseAfterClose>
2222
<swagger.version>2.2.26</swagger.version>
2323
<jackson.version>2.14.2</jackson.version>
24+
<jex.version>3.0-SNAPSHOT</jex.version>
2425
<avaje.prisms.version>1.35</avaje.prisms.version>
26+
<project.build.outputTimestamp>2024-10-28T03:18:56Z</project.build.outputTimestamp>
2527
<module-info.shade>${project.build.directory}${file.separator}module-info.shade</module-info.shade>
2628
</properties>
2729

@@ -44,7 +46,6 @@
4446
<module>http-inject-plugin</module>
4547
<module>http-generator-core</module>
4648
<module>http-generator-javalin</module>
47-
<module>http-generator-jex</module>
4849
<module>http-generator-sigma</module>
4950
<module>http-generator-client</module>
5051
</modules>
@@ -68,6 +69,7 @@
6869
<module>htmx-nima</module>
6970
<module>htmx-nima-jstache</module>
7071
<module>http-generator-helidon</module>
72+
<module>http-generator-jex</module>
7173
</modules>
7274
</profile>
7375
<profile>

tests/pom.xml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<junit.version>5.11.3</junit.version>
1616
<assertj.version>3.26.3</assertj.version>
1717
<jackson.version>2.18.1</jackson.version>
18-
<jex.version>2.5</jex.version>
18+
<jex.version>3.0-RC1</jex.version>
1919
<avaje-inject.version>11.0</avaje-inject.version>
2020
<nima.version>4.1.4</nima.version>
2121
<javalin.version>6.3.0</javalin.version>
@@ -24,9 +24,7 @@
2424
<modules>
2525
<module>test-javalin</module>
2626
<module>test-javalin-jsonb</module>
27-
<module>test-jex</module>
2827
<module>test-client</module>
29-
<module>test-client-generation</module>
3028
<module>test-sigma</module>
3129
</modules>
3230

@@ -38,19 +36,21 @@
3836
</activation>
3937
<modules>
4038
<module>test-nima</module>
39+
<module>test-jex</module>
4140
<module>test-nima-jsonb</module>
4241
<module>test-nima-htmx</module>
42+
<module>test-client-generation</module>
4343
</modules>
4444
</profile>
4545
</profiles>
46-
46+
4747
<dependencies>
4848
<dependency>
4949
<groupId>io.avaje</groupId>
5050
<artifactId>avaje-validator</artifactId>
5151
<version>2.3</version>
5252
</dependency>
53-
53+
5454
<dependency>
5555
<groupId>io.avaje</groupId>
5656
<artifactId>avaje-validator-constraints</artifactId>
@@ -62,7 +62,7 @@
6262
<artifactId>avaje-validator-generator</artifactId>
6363
<version>2.3</version>
6464
</dependency>
65-
65+
6666
</dependencies>
6767

6868
</project>

tests/test-client-generation/pom.xml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161

6262
<dependency>
6363
<groupId>io.avaje</groupId>
64-
<artifactId>avaje-jex-jetty</artifactId>
64+
<artifactId>avaje-jex</artifactId>
6565
<version>${jex.version}</version>
6666
</dependency>
6767
<dependency>
@@ -90,7 +90,19 @@
9090
<version>${assertj.version}</version>
9191
<scope>test</scope>
9292
</dependency>
93-
93+
94+
<!-- needed for mvnd parallel builds-->
95+
<dependency>
96+
<groupId>io.avaje</groupId>
97+
<artifactId>avaje-http-client-generator</artifactId>
98+
<version>${project.version}</version>
99+
</dependency>
100+
<dependency>
101+
<groupId>io.avaje</groupId>
102+
<artifactId>avaje-http-jex-generator</artifactId>
103+
<version>${project.version}</version>
104+
</dependency>
105+
94106
</dependencies>
95107

96108
<build>

tests/test-client-generation/src/main/java/org/example/server/Main.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22

33
import io.avaje.inject.BeanScope;
44
import io.avaje.jex.Jex;
5-
import io.avaje.jex.Routing;
6-
7-
import java.util.List;
85

96
public class Main {
107

@@ -19,10 +16,7 @@ public static Jex.Server start(int port) {
1916

2017
public static Jex.Server start(int port, BeanScope context) {
2118

22-
final List<Routing.Service> services = context.list(Routing.Service.class);
23-
24-
final Jex jex = Jex.create();
25-
jex.routing().addAll(services);
19+
final Jex jex = Jex.create().configureWith(context);
2620
return jex.port(port).start();
2721
}
2822
}

0 commit comments

Comments
 (0)