From 311636554a97dd7c99a5f68b415ca99795c1c326 Mon Sep 17 00:00:00 2001 From: Unknow Date: Fri, 29 May 2026 13:15:18 +0200 Subject: [PATCH] JaxRs fix invalid throw in simple service and add test on simple service --- .github/http_test.sh | 2 +- bench/tests.sh | 2 +- .../maven/jaxrs/JaxRsServletBuilder.java | 72 ++++++++++++------- .../server/maven/jaxrs/MediaTypesBuilder.java | 36 ++++++---- .../java/unknow/server/http/test/Live.java | 18 +++++ .../java/unknow/server/http/test/Rest.java | 20 +++--- 6 files changed, 100 insertions(+), 50 deletions(-) create mode 100644 unknow-server-test/unknow-server-test-pojo/src/main/java/unknow/server/http/test/Live.java diff --git a/.github/http_test.sh b/.github/http_test.sh index ba4903e2..bff1fd1f 100644 --- a/.github/http_test.sh +++ b/.github/http_test.sh @@ -75,5 +75,5 @@ cat out.xml | xml_parse | tee out | diff - .github/xml/wrapped_res.xml || die 'w curl -s -XGET "$URL/ws?wsdl" | xmllint --format - >/dev/null || die 'webservice wsdl' -curl -s -XPOST --data-binary @.github/truc.binpb -H 'Accept:application/x-protobuf' -H 'Content-type: application/x-protobuf' -o out.binpb "$URL/rest/q" && diff -q .github/truc.binpb out.binpb +curl -s -XPOST --data-binary @.github/truc.binpb -H 'Accept:application/x-protobuf' -H 'Content-type: application/x-protobuf' -o out.binpb "$URL/rest" && diff -q .github/truc.binpb out.binpb diff --git a/bench/tests.sh b/bench/tests.sh index d135aafd..56d23566 100644 --- a/bench/tests.sh +++ b/bench/tests.sh @@ -31,7 +31,7 @@ test missing -m 0.02 -XGET http://$h:8080/missing?[1-$c] test simple -m 0.02 -XGET http://$h:8080/test?[1-$c] test ssl -m 0.09 -XGET -k --http1.1 https://$h:8443/test?[1-$c] test ws -m 0.02 -XPOST -d@bench/req/ws.xml http://$h:8080/ws?[1-$c] -test rest -m 0.02 -XPOST -H 'Accept: application/json' -H 'Content-type: application/json' -d'{"v":"toto"}' http://$h:8080/rest/[1-$c] +test rest -m 0.02 -XPOST -H 'Accept: application/json' -H 'Content-type: application/json' -d'{"v":"toto"}' http://$h:8080/rest/?[1-$c] test http2 -m 0.09 -XGET -k --http2 https://$h:8443/test?[1-$c] test post -m 0.02 -XPOST -d@data -k http://$h:8080/test?[1-$c] test close -m 0.02 -XPOST -d@data -k -H 'Connection: close' http://$h:8080/test?[1-$c] \ No newline at end of file diff --git a/unknow-server-maven/src/main/java/unknow/server/maven/jaxrs/JaxRsServletBuilder.java b/unknow-server-maven/src/main/java/unknow/server/maven/jaxrs/JaxRsServletBuilder.java index a0ad6f9c..382c249d 100644 --- a/unknow-server-maven/src/main/java/unknow/server/maven/jaxrs/JaxRsServletBuilder.java +++ b/unknow-server-maven/src/main/java/unknow/server/maven/jaxrs/JaxRsServletBuilder.java @@ -83,6 +83,7 @@ import unknow.server.maven.jaxrs.JaxrsParam.JaxrsBodyParam; /** + * Build a jaxrs servlet * @author unknow */ public class JaxRsServletBuilder { @@ -146,6 +147,11 @@ public JaxRsServletBuilder(CompilationUnit cu, Map existingClass } } + /** + * convert a path mapping to a java class name + * @param path the path + * @return the class name + */ private static String toClass(String path) { StringBuilder sb = new StringBuilder("Jaxrs"); String[] split = path.split("[^a-zA-Z0-9_$*]+"); @@ -278,9 +284,11 @@ private void buildOptions(String name, Set methods) { } /** - * @param p - * @param string - * @param b + * create all required converter and add them to servlet fields + * @param p the param + * @param n converter field name + * @param i parameter index + * @param b static block */ private void processConverter(JaxrsParam p, String n, int i, BlockStmt b) { if (p instanceof JaxrsBeanParam) @@ -315,15 +323,21 @@ private void processConverter(JaxrsParam p, String n, int i, BlockStmt b) { } /** - * @param method - * @param mapping - * @throws MojoFailureException + * build the call for one method on one path + * @param name java method name + * @param list list of mapping on this path and method + * @throws MojoFailureException in case of error */ private void buildMethod(String name, List list) throws MojoFailureException { - BlockStmt b = cl.addMethod(name, CodeGenUtils.PRIVATE).addParameter(types.getClass(JaxrsReq.class), "req") - .addParameter(types.getClass(HttpServletResponse.class), "res").addThrownException(Exception.class).createBody(); - + BlockStmt b = new BlockStmt(); + cl.addMethod(name, CodeGenUtils.PRIVATE).addParameter(types.getClass(JaxrsReq.class), "req").addParameter(types.getClass(HttpServletResponse.class), "res") + .createBody() + .addStatement(new TryStmt(b, + CodeGenUtils.list(new CatchClause(new com.github.javaparser.ast.body.Parameter(types.getClass(Throwable.class), "e"), + new BlockStmt().addStatement(new MethodCallExpr(new TypeExpr(types.getClass(JaxrsContext.class)), "sendError", + CodeGenUtils.list(new NameExpr("req"), new NameExpr("e"), new NameExpr("res")))))), + null)); Map, Collection> consume = buildConsumeMap(list); Iterator, Collection>> it = consume.entrySet().iterator(); List def = null; @@ -371,8 +385,14 @@ private static Map, Collection> buildConsumeMap(List< return group; } - private Statement buildProduces(BlockStmt b, Collection mappings) throws MojoFailureException { - + /** + * build the block to route with the accept header to the right service method + * @param b where to add statement + * @param mappings the mapping to manage + * @return b + * @throws MojoFailureException in case of error + */ + private BlockStmt buildProduces(BlockStmt b, Collection mappings) throws MojoFailureException { Map produce = new HashMap<>(); for (JaxrsMapping m : mappings) { for (String p : m.produce) { @@ -413,6 +433,11 @@ private Statement buildProduces(BlockStmt b, Collection mappings) return b; } + /** + * build the method that will parse service parameter, call the service method and write the response + * @param mapping the mapping + * @param services service class -> Expression + */ private void buildCall(JaxrsMapping mapping, Map services) { BlockStmt b = cl.addMethod(mapping.v + "$call", CodeGenUtils.PSF).addParameter(types.getClass(JaxrsReq.class), "r") .addParameter(types.getClass(HttpServletResponse.class), "res").addThrownException(types.getClass(Exception.class)).createBody(); @@ -440,8 +465,9 @@ private void buildCall(JaxrsMapping mapping, Map services) { } /** - * @param key - * @param value + * get the Exception to conver a param to java type + * @param p the param + * @return the excpetion to convert the param */ private Expression getParam(JaxrsParam p) { @@ -459,6 +485,10 @@ private interface ServiceBuilder { void build() throws MojoFailureException; } + /** + * service without pattern + * will implements do() directly + */ private class SimpleService implements ServiceBuilder { @Override @@ -607,18 +637,10 @@ private void buildService(String name, Map> methods) for (String method : methods.keySet()) i = new IfStmt(new MethodCallExpr(CodeGenUtils.text(method), "equals", CodeGenUtils.list(m)), new ExpressionStmt(new MethodCallExpr(name + "$" + method.toLowerCase(), p)), i); - BlockStmt b = new BlockStmt().addStatement(CodeGenUtils.assign(types.getClass(String.class), "m", new MethodCallExpr(new NameExpr("r"), "getMethod"))) - .addStatement(i); - - cl.addMethod(name, - CodeGenUtils.PRIVATE).addParameter(types.getClass(JaxrsReq.class), - "r") - .addParameter(types.getClass(HttpServletResponse.class), "res").createBody() - .addStatement(new TryStmt(b, - CodeGenUtils.list(new CatchClause(new com.github.javaparser.ast.body.Parameter(types.getClass(Throwable.class), "e"), - new BlockStmt().addStatement(new MethodCallExpr(new TypeExpr(types.getClass(JaxrsContext.class)), "sendError", - CodeGenUtils.list(new NameExpr("r"), new NameExpr("e"), new NameExpr("res")))))), - null)); + + cl.addMethod(name, CodeGenUtils.PRIVATE).addParameter(types.getClass(JaxrsReq.class), "r").addParameter(types.getClass(HttpServletResponse.class), "res") + .addThrownException(types.getClass(IOException.class)).createBody() + .addStatement(CodeGenUtils.assign(types.getClass(String.class), "m", new MethodCallExpr(new NameExpr("r"), "getMethod"))).addStatement(i); } } diff --git a/unknow-server-maven/src/main/java/unknow/server/maven/jaxrs/MediaTypesBuilder.java b/unknow-server-maven/src/main/java/unknow/server/maven/jaxrs/MediaTypesBuilder.java index 893f94e4..d9e3907e 100644 --- a/unknow-server-maven/src/main/java/unknow/server/maven/jaxrs/MediaTypesBuilder.java +++ b/unknow-server-maven/src/main/java/unknow/server/maven/jaxrs/MediaTypesBuilder.java @@ -1,6 +1,3 @@ -/** - * - */ package unknow.server.maven.jaxrs; import java.util.ArrayList; @@ -29,6 +26,7 @@ import unknow.server.http.jaxrs.MTPredicate; /** + * Build MediaTypes class with added MTPredicate and MediaType * @author unknow */ public class MediaTypesBuilder { @@ -71,23 +69,31 @@ public MediaTypesBuilder(CompilationUnit cu, Map existingClass) } + /** + * write the MediaTypes class if needed + * @param writer writer to write to + * @throws MojoExecutionException in case od error + */ public void save(CompilationUnitWriter writer) throws MojoExecutionException { if (!predicates.isEmpty() || mts.size() > 13) writer.write(cu); } + /** + * get an exception to an MediaType + * @param f factory to add the required import + * @param t mediaType + * @return the exception + */ public Expression type(TypeFactory f, String t) { + String field = DEFAULT.get(t); + if (field != null) + return new FieldAccessExpr(new TypeExpr(f.getClass(MediaType.class)), field); + Expression n = mts.get(t); if (n != null) return n; - String field = DEFAULT.get(t); - if (field != null) { - n = new FieldAccessExpr(new TypeExpr(f.getClass(MediaType.class)), field); - mts.put(t, n); - return n; - } - String[] split = t.split("/"); String name = t.toUpperCase().replaceAll("[^_a-zA-Z]", "_"); @@ -98,7 +104,13 @@ public Expression type(TypeFactory f, String t) { return n; } - public Expression predicate(TypeFactory t, Collection mediaTypes) { + /** + * get an exception to an MTPredicate + * @param f factory to add the required import + * @param mediaTypes types accepted by the predicate + * @return the exception + */ + public Expression predicate(TypeFactory f, Collection mediaTypes) { String k = ""; if (!mediaTypes.contains("*/*")) { List l = new ArrayList<>(mediaTypes); @@ -128,7 +140,7 @@ else if (mediaTypes.size() == 1) } cl.addFieldWithInitializer(types.getClass(MTPredicate.class), name, e, CodeGenUtils.PUBLIC_STATIC); - predicates.put(k, n = new FieldAccessExpr(new TypeExpr(t.getClass(cl)), name)); + predicates.put(k, n = new FieldAccessExpr(new TypeExpr(f.getClass(cl)), name)); return n; } } diff --git a/unknow-server-test/unknow-server-test-pojo/src/main/java/unknow/server/http/test/Live.java b/unknow-server-test/unknow-server-test-pojo/src/main/java/unknow/server/http/test/Live.java new file mode 100644 index 00000000..3df715a0 --- /dev/null +++ b/unknow-server-test/unknow-server-test-pojo/src/main/java/unknow/server/http/test/Live.java @@ -0,0 +1,18 @@ +package unknow.server.http.test; + +import java.io.IOException; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +@WebServlet("/-/live") +public class Live extends HttpServlet { + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // ok + } +} diff --git a/unknow-server-test/unknow-server-test-pojo/src/main/java/unknow/server/http/test/Rest.java b/unknow-server-test/unknow-server-test-pojo/src/main/java/unknow/server/http/test/Rest.java index 5f1f8740..21de514a 100644 --- a/unknow-server-test/unknow-server-test-pojo/src/main/java/unknow/server/http/test/Rest.java +++ b/unknow-server-test/unknow-server-test-pojo/src/main/java/unknow/server/http/test/Rest.java @@ -28,13 +28,13 @@ /** * @author unknow */ -@Path("/{q}") +@Path("/") @Produces("application/json") public class Rest { private static final Logger logger = LoggerFactory.getLogger(Rest.class); @GET - @Path("t") + @Path("{q}/t") @SuppressWarnings("unused") public void t(@PathParam("q") String q) throws InterruptedException { Thread.sleep(3000); @@ -44,26 +44,25 @@ public void t(@PathParam("q") String q) throws InterruptedException { @GET @Path("q/{v}") @SuppressWarnings("unused") - public void q(@PathParam("q") String q, @PathParam("v") String v) { // ok + public void q(@PathParam("v") String v) { // ok } @POST - public void oneWay(@PathParam("q") String q, @BeanParam Bean bean) { - logger.info("oneWay>> q: '{}' bean: {}", q, bean); + public void oneWay(@BeanParam Bean bean) throws Exception { + logger.info("oneWay>> bean: {}", bean); } @PUT @Consumes({ "application/json", "application/x-ndjson" }) - public Response response(@PathParam("q") String q, @FormParam("k") String k) { - logger.info("response>> q: '{}' bean: {}", q, k); + public Response response(@FormParam("k") String k) { + logger.info("response>> bean: {}", k); return Response.status(200).entity("echo").build(); } @POST @Consumes({ "application/x-protobuf", "application/json", "application/jsonl", "application/x-ndjson" }) @Produces({ "application/x-protobuf", "application/json", "application/jsonl", "application/x-ndjson" }) - @SuppressWarnings("unused") - public Truc call(@PathParam("q") String q, Truc truc) { + public Truc call(Truc truc) { return truc; } @@ -71,8 +70,7 @@ public Truc call(@PathParam("q") String q, Truc truc) { @Path("list") @Consumes({ "application/x-protobuf", "application/json", "application/jsonl", "application/x-ndjson" }) @Produces({ "application/x-protobuf", "application/json", "application/jsonl", "application/x-ndjson" }) - @SuppressWarnings("unused") - public Collection list(@PathParam("q") String q, Collection truc) { + public Collection list(Collection truc) { return truc; }