Skip to content

Update Jex Generation #517

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions http-api/src/main/java/io/avaje/http/api/Options.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.avaje.http.api;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

/**
* Marks a method that handles HTTP OPTIONS requests.
*/
@Target(METHOD)
@Retention(RUNTIME)
@HttpMethod("OPTIONS")
public @interface Options {

/** Specify the path. */
String value() default "";

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ public enum CoreWebMethod implements WebMethod {
PUT(200, 204),
PATCH(200, 204),
DELETE(200, 204),
OPTIONS(200, 204),
ERROR(500),
FILTER(0),
OTHER(0, 0);

private int statusCode;
private int voidStatusCode;
private final int statusCode;
private final int voidStatusCode;

CoreWebMethod(int statusCode, int voidStatusCode) {
this.statusCode = statusCode;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package io.avaje.http.generator.jex;

import static io.avaje.http.generator.core.ProcessingContext.isAssignable2Interface;
import static io.avaje.http.generator.core.ProcessingContext.logError;
import static io.avaje.http.generator.core.ProcessingContext.platform;

import java.io.IOException;
import java.util.List;

import io.avaje.http.generator.core.*;
Expand All @@ -15,18 +19,35 @@ class ControllerMethodWriter {
private final Append writer;
private final WebMethod webMethod;
private final boolean instrumentContext;
private final boolean isFilter;

ControllerMethodWriter(MethodReader method, Append writer) {
this.method = method;
this.writer = writer;
this.webMethod = method.webMethod();
this.instrumentContext = method.instrumentContext();
this.isFilter = webMethod == CoreWebMethod.FILTER;
if (isFilter) {
validateMethod();
}
}

private void validateMethod() {
if (method.params().stream().map(MethodParam::shortType).noneMatch("FilterChain"::equals)) {
logError(method.element(), "Filters must contain a FilterChain parameter");
}
}

void writeRouting() {
final PathSegments segments = method.pathSegments();
final String fullPath = segments.fullPath();
writer.append(" routing.%s(\"%s\", this::_%s)", webMethod.name().toLowerCase(), fullPath, method.simpleName());

if (isFilter) {
writer.append(" routing.filter(this::_%s)", method.simpleName());
} else {
writer.append(" routing.%s(\"%s\", this::_%s)", webMethod.name().toLowerCase(), fullPath, method.simpleName());
}

List<String> roles = method.roles();
if (!roles.isEmpty()) {
writer.append(".withRoles(");
Expand All @@ -42,7 +63,17 @@ void writeRouting() {
}

void writeHandler(boolean requestScoped) {
writer.append(" private void _%s(Context ctx) {", method.simpleName()).eol();

if (method.isErrorMethod()) {
writer.append(" private void _%s(Context ctx, %s ex)", method.simpleName(), method.exceptionShortName());
} else if (isFilter) {
writer.append(" private void _%s(Context ctx, FilterChain chain)", method.simpleName());
} else {
writer.append(" private void _%s(Context ctx)", method.simpleName());
}

writer.append(" throws IOException {", method.simpleName()).eol();

write(requestScoped);
writer.append(" }").eol().eol();
}
Expand All @@ -61,7 +92,9 @@ private void write(boolean requestScoped) {

final List<MethodParam> params = method.params();
for (MethodParam param : params) {
param.writeCtxGet(writer, segments);
if (!isExceptionOrFilterChain(param)) {
param.writeCtxGet(writer, segments);
}
}
if (method.includeValidate()) {
for (MethodParam param : params) {
Expand All @@ -85,7 +118,14 @@ private void write(boolean requestScoped) {
if (i > 0) {
writer.append(", ");
}
params.get(i).buildParamName(writer);
final var param = params.get(i);
if (isAssignable2Interface(param.utype().mainType(), "java.lang.Exception")) {
writer.append("ex");
} else if ("FilterChain".equals(param.shortType())) {
writer.append("chain");
} else {
param.buildParamName(writer);
}
}
writer.append(")");
if (!method.isVoid()) {
Expand All @@ -111,4 +151,9 @@ private void writeContextReturn() {
writer.append("ctx.contentType(\"%s\").write(", produces);
}
}

private static boolean isExceptionOrFilterChain(MethodParam param) {
return isAssignable2Interface(param.utype().mainType(), "java.lang.Exception")
|| "FilterChain".equals(param.shortType());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,18 @@ class ControllerWriter extends BaseControllerWriter {
private static final String AT_GENERATED = "@Generated(\"avaje-jex-generator\")";
private static final String API_CONTEXT = "io.avaje.jex.Context";
private static final String API_ROUTING = "io.avaje.jex.Routing";
private static final String API_ROUTING_SERVICE = "io.avaje.jex.Routing.Service";

ControllerWriter(ControllerReader reader) throws IOException {
super(reader);
reader.addImportType(API_CONTEXT);
reader.addImportType(API_ROUTING);
reader.addImportType(API_ROUTING_SERVICE);
reader.addImportType("java.io.IOException");

if (reader.methods().stream()
.map(MethodReader::webMethod)
.anyMatch(w -> CoreWebMethod.FILTER == w)) {
reader.addImportType("io.avaje.jex.FilterChain");
}
}

void write() {
Expand Down Expand Up @@ -60,7 +65,7 @@ private void writeRouting(MethodReader method) {
private void writeClassStart() {
writer.append(AT_GENERATED).eol();
writer.append(diAnnotation()).eol();
writer.append("public class ").append(shortName).append("$Route implements Routing.Service {").eol().eol();
writer.append("public class ").append(shortName).append("$Route implements Routing.HttpService {").eol().eol();

String controllerName = "controller";
String controllerType = shortName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,17 @@ public boolean isBodyMethodParam() {
}

@Override
public String bodyAsClass(UType uType) {
if ("java.lang.String".equals(uType.full())) {
public String bodyAsClass(UType type) {

if ("java.io.InputStream".equals(type.full())) {
return "ctx.bodyInputStream()";
} else if ("java.lang.String".equals(type.full())) {
return "ctx.body()";
} else if ("byte[]".equals(type.full())) {
return "ctx.bodyAsBytes()";
}
return "ctx.bodyAsClass(" + uType.mainType() + ".class)";

return "ctx.bodyAsClass(" + type.mainType() + ".class)";
}

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

@Override
public void writeReadMapParameter(Append writer, ParamType paramType) {

switch (paramType) {
case QUERYPARAM:
writer.append("ctx.queryParamMap()");
break;
case FORM:
case FORMPARAM:
writer.append("ctx.formParamMap()");
break;
default:
throw new UnsupportedOperationException(
"Only Query/Form Params have Map<String, List<String>> supported in Jex");
}
}

@Override
public void writeReadCollectionParameter(Append writer, ParamType paramType, String paramName) {
if (paramType != ParamType.QUERYPARAM) {
throw new UnsupportedOperationException(
"Only MultiValue Query Params are supported in Jex");
switch (paramType) {
case QUERYPARAM:
writer.append("ctx.queryParams(\"%s\")", paramName);
break;
case FORMPARAM:
writer.append("ctx.formParams(\"%s\")", paramName);
break;
default:
throw new UnsupportedOperationException(
"Only MultiValue Form/Query Params are supported in Jex");
}
writer.append("ctx.queryParams(\"%s\")", paramName);
}

@Override
public void writeReadCollectionParameter(
Append writer, ParamType paramType, String paramName, List<String> paramDefault) {
if (paramType != ParamType.QUERYPARAM) {
throw new UnsupportedOperationException(
"Only MultiValue Query Params are supported in Jex");

switch (paramType) {
case QUERYPARAM:
writer.append(
"withDefault(ctx.queryParams(\"%s\"), java.util.List.of(\"%s\"))",
paramName, String.join(",", paramDefault));
break;
case FORMPARAM:
writer.append(
"withDefault(ctx.formParams(\"%s\"), java.util.List.of(\"%s\"))",
paramName, String.join(",", paramDefault));
break;
default:
throw new UnsupportedOperationException(
"Only MultiValue Form/Query Params are supported in Jex");
}
writer.append("withDefault(ctx.queryParams(\"%s\"), java.util.List.of(\"%s\"))", paramName, String.join(",", paramDefault));
}

@Override
public void writeAcceptLanguage(Append writer) {
writer.append("ctx.header(\"%s\")", Constants.ACCEPT_LANGUAGE);
}

}
4 changes: 3 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
<nexus.staging.autoReleaseAfterClose>true</nexus.staging.autoReleaseAfterClose>
<swagger.version>2.2.26</swagger.version>
<jackson.version>2.14.2</jackson.version>
<jex.version>3.0-SNAPSHOT</jex.version>
<avaje.prisms.version>1.35</avaje.prisms.version>
<project.build.outputTimestamp>2024-10-28T03:18:56Z</project.build.outputTimestamp>
<module-info.shade>${project.build.directory}${file.separator}module-info.shade</module-info.shade>
</properties>

Expand All @@ -44,7 +46,6 @@
<module>http-inject-plugin</module>
<module>http-generator-core</module>
<module>http-generator-javalin</module>
<module>http-generator-jex</module>
<module>http-generator-sigma</module>
<module>http-generator-client</module>
</modules>
Expand All @@ -68,6 +69,7 @@
<module>htmx-nima</module>
<module>htmx-nima-jstache</module>
<module>http-generator-helidon</module>
<module>http-generator-jex</module>
</modules>
</profile>
<profile>
Expand Down
12 changes: 6 additions & 6 deletions tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<junit.version>5.11.3</junit.version>
<assertj.version>3.26.3</assertj.version>
<jackson.version>2.18.1</jackson.version>
<jex.version>2.5</jex.version>
<jex.version>3.0-RC1</jex.version>
<avaje-inject.version>11.0</avaje-inject.version>
<nima.version>4.1.4</nima.version>
<javalin.version>6.3.0</javalin.version>
Expand All @@ -24,9 +24,7 @@
<modules>
<module>test-javalin</module>
<module>test-javalin-jsonb</module>
<module>test-jex</module>
<module>test-client</module>
<module>test-client-generation</module>
<module>test-sigma</module>
</modules>

Expand All @@ -38,19 +36,21 @@
</activation>
<modules>
<module>test-nima</module>
<module>test-jex</module>
<module>test-nima-jsonb</module>
<module>test-nima-htmx</module>
<module>test-client-generation</module>
</modules>
</profile>
</profiles>

<dependencies>
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-validator</artifactId>
<version>2.3</version>
</dependency>

<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-validator-constraints</artifactId>
Expand All @@ -62,7 +62,7 @@
<artifactId>avaje-validator-generator</artifactId>
<version>2.3</version>
</dependency>

</dependencies>

</project>
16 changes: 14 additions & 2 deletions tests/test-client-generation/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@

<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-jex-jetty</artifactId>
<artifactId>avaje-jex</artifactId>
<version>${jex.version}</version>
</dependency>
<dependency>
Expand Down Expand Up @@ -90,7 +90,19 @@
<version>${assertj.version}</version>
<scope>test</scope>
</dependency>


<!-- needed for mvnd parallel builds-->
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-http-client-generator</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-http-jex-generator</artifactId>
<version>${project.version}</version>
</dependency>

</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@

import io.avaje.inject.BeanScope;
import io.avaje.jex.Jex;
import io.avaje.jex.Routing;

import java.util.List;

public class Main {

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

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

final List<Routing.Service> services = context.list(Routing.Service.class);

final Jex jex = Jex.create();
jex.routing().addAll(services);
final Jex jex = Jex.create().configureWith(context);
return jex.port(port).start();
}
}
Loading