From 8d57c4bbf622e9dc17608b39ccfdbea2226e7889 Mon Sep 17 00:00:00 2001 From: Edgar Espina Date: Sat, 22 Jun 2024 19:57:14 -0300 Subject: [PATCH] jooby-apt: Java strings not escaped properly in mvc source code generation. - fix #3455 - shade commons-text + use automatic-module-name --- modules/jooby-apt/pom.xml | 54 +++++++++++++------ .../java/io/jooby/internal/apt/CodeBlock.java | 4 +- .../java/io/jooby/internal/apt/MvcRoute.java | 2 +- .../apt/RouteAttributesGenerator.java | 22 ++++---- .../src/test/java/tests/i2417/Issue2417.java | 3 +- .../src/test/java/tests/i3455/C3455.java | 21 ++++++++ .../src/test/java/tests/i3455/Issue3455.java | 26 +++++++++ 7 files changed, 101 insertions(+), 31 deletions(-) create mode 100644 modules/jooby-apt/src/test/java/tests/i3455/C3455.java create mode 100644 modules/jooby-apt/src/test/java/tests/i3455/Issue3455.java diff --git a/modules/jooby-apt/pom.xml b/modules/jooby-apt/pom.xml index 26f7399924..b29cdab271 100644 --- a/modules/jooby-apt/pom.xml +++ b/modules/jooby-apt/pom.xml @@ -26,6 +26,12 @@ test + + org.apache.commons + commons-text + 1.12.0 + + com.google.testing.compile @@ -110,33 +116,47 @@ - org.moditect - moditect-maven-plugin - ${moditec.version} + org.apache.maven.plugins + maven-shade-plugin - generate-module-info + fat-jar package - add-module-info + shade - true - false - - - io.jooby.apt - - !io.jooby.internal.*; - *; - - - + true + + + org.apache.commons:commons-text + + + + + org.apache.commons:commons-text + + org/apache/commons/text/** + + + + + + org.apache.commons.text + ${shaded.package}.commonstext + + + + + + io.jooby.apt + + + - diff --git a/modules/jooby-apt/src/main/java/io/jooby/internal/apt/CodeBlock.java b/modules/jooby-apt/src/main/java/io/jooby/internal/apt/CodeBlock.java index cfa6e1dfc4..40a287eb5d 100644 --- a/modules/jooby-apt/src/main/java/io/jooby/internal/apt/CodeBlock.java +++ b/modules/jooby-apt/src/main/java/io/jooby/internal/apt/CodeBlock.java @@ -5,6 +5,8 @@ */ package io.jooby.internal.apt; +import static org.apache.commons.text.StringEscapeUtils.ESCAPE_JAVA; + import java.util.List; import java.util.stream.Stream; @@ -22,7 +24,7 @@ public static String of(CharSequence... sequence) { } public static CharSequence string(CharSequence value) { - return "\"" + value + "\""; + return "\"" + ESCAPE_JAVA.translate(value) + "\""; } public static CharSequence clazz(boolean kt) { diff --git a/modules/jooby-apt/src/main/java/io/jooby/internal/apt/MvcRoute.java b/modules/jooby-apt/src/main/java/io/jooby/internal/apt/MvcRoute.java index 1fe8de8321..995cc64224 100644 --- a/modules/jooby-apt/src/main/java/io/jooby/internal/apt/MvcRoute.java +++ b/modules/jooby-apt/src/main/java/io/jooby/internal/apt/MvcRoute.java @@ -133,7 +133,7 @@ public List generateMapping(boolean kt) { block.add(statement(indent(2), ".setExecutorKey(", string(dispatch), ")"))); /* attributes */ attributeGenerator - .toSourceCode(this, indent(2)) + .toSourceCode(this, 2) .ifPresent( attributes -> block.add(statement(indent(2), ".setAttributes(", attributes, ")"))); /* returnType */ diff --git a/modules/jooby-apt/src/main/java/io/jooby/internal/apt/RouteAttributesGenerator.java b/modules/jooby-apt/src/main/java/io/jooby/internal/apt/RouteAttributesGenerator.java index a9f3f05f99..4dbf2bcf93 100644 --- a/modules/jooby-apt/src/main/java/io/jooby/internal/apt/RouteAttributesGenerator.java +++ b/modules/jooby-apt/src/main/java/io/jooby/internal/apt/RouteAttributesGenerator.java @@ -6,6 +6,7 @@ package io.jooby.internal.apt; import static io.jooby.apt.JoobyProcessor.Options.SKIP_ATTRIBUTE_ANNOTATIONS; +import static io.jooby.internal.apt.CodeBlock.indent; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -53,16 +54,16 @@ public RouteAttributesGenerator(MvcContext context) { this.skip = Options.stringListOpt(environment, SKIP_ATTRIBUTE_ANNOTATIONS); } - public Optional toSourceCode(MvcRoute route, String indent) { + public Optional toSourceCode(MvcRoute route, int indent) { var attributes = annotationMap(route.getMethod()); if (attributes.isEmpty()) { return Optional.empty(); } else { - return Optional.of(toSourceCode(annotationMap(route.getMethod()), indent)); + return Optional.of(toSourceCode(annotationMap(route.getMethod()), indent + 6)); } } - private String toSourceCode(Map attributes, String indent) { + private String toSourceCode(Map attributes, int indent) { var buffer = new StringBuilder(); var separator = ",\n"; var pairPrefix = ""; @@ -75,12 +76,11 @@ private String toSourceCode(Map attributes, String indent) { factoryMethod = "ofEntries"; } buffer.append("java.util.Map.").append(factoryMethod).append("(\n"); - var lineIndent = indent + " "; for (var e : attributes.entrySet()) { - buffer.append(lineIndent); + buffer.append(indent(indent + 4)); buffer.append(pairPrefix); - buffer.append("\"").append(e.getKey()).append("\"").append(", "); - buffer.append(valueToSourceCode(e.getValue(), lineIndent)); + buffer.append(CodeBlock.string(e.getKey())).append(", "); + buffer.append(valueToSourceCode(e.getValue(), indent + 4)); buffer.append(pairSuffix).append(separator); } buffer.setLength(buffer.length() - separator.length()); @@ -88,13 +88,13 @@ private String toSourceCode(Map attributes, String indent) { return buffer.toString(); } - private Object valueToSourceCode(Object value, String indent) { + private Object valueToSourceCode(Object value, int indent) { if (value instanceof String) { - return "\"" + value + "\""; + return CodeBlock.string((String) value); } else if (value instanceof Character) { return "'" + value + "'"; } else if (value instanceof Map attributeMap) { - return "\n " + indent + toSourceCode(attributeMap, indent + " "); + return "\n " + indent(indent) + toSourceCode(attributeMap, indent + 1); } else if (value instanceof List list) { return valueToSourceCode(list, indent); } else if (value instanceof EnumValue enumValue) { @@ -116,7 +116,7 @@ private Object valueToSourceCode(Object value, String indent) { } } - private String valueToSourceCode(List values, String indent) { + private String valueToSourceCode(List values, int indent) { var buffer = new StringBuilder(); buffer.append("java.util.List.of("); var separator = ", "; diff --git a/modules/jooby-apt/src/test/java/tests/i2417/Issue2417.java b/modules/jooby-apt/src/test/java/tests/i2417/Issue2417.java index 6465bba41d..6a6e929ae1 100644 --- a/modules/jooby-apt/src/test/java/tests/i2417/Issue2417.java +++ b/modules/jooby-apt/src/test/java/tests/i2417/Issue2417.java @@ -18,7 +18,8 @@ public class Issue2417 { public void shouldNotIgnoreAnnotationOnParam() throws Exception { new ProcessorRunner(new C2417()) .withRouter( - app -> { + (app, source) -> { + System.out.println(source); MockRouter router = new MockRouter(app); assertEquals( "2417", diff --git a/modules/jooby-apt/src/test/java/tests/i3455/C3455.java b/modules/jooby-apt/src/test/java/tests/i3455/C3455.java new file mode 100644 index 0000000000..04ca3cd685 --- /dev/null +++ b/modules/jooby-apt/src/test/java/tests/i3455/C3455.java @@ -0,0 +1,21 @@ +/* + * Jooby https://jooby.io + * Apache License Version 2.0 https://jooby.io/LICENSE.txt + * Copyright 2014 Edgar Espina + */ +package tests.i3455; + +import edu.umd.cs.findbugs.annotations.NonNull; +import io.jooby.annotation.GET; +import io.jooby.annotation.Path; +import io.jooby.annotation.QueryParam; +import io.swagger.v3.oas.annotations.media.Schema; + +@Path("/\"path") +public class C3455 { + @GET("/required\"-string-param") + @Schema(description = "test\"ttttt") + public String requiredStringParam(@QueryParam("value\"") @NonNull String value) { + return value; + } +} diff --git a/modules/jooby-apt/src/test/java/tests/i3455/Issue3455.java b/modules/jooby-apt/src/test/java/tests/i3455/Issue3455.java new file mode 100644 index 0000000000..5d5d26e5f6 --- /dev/null +++ b/modules/jooby-apt/src/test/java/tests/i3455/Issue3455.java @@ -0,0 +1,26 @@ +/* + * Jooby https://jooby.io + * Apache License Version 2.0 https://jooby.io/LICENSE.txt + * Copyright 2014 Edgar Espina + */ +package tests.i3455; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +import io.jooby.apt.ProcessorRunner; + +public class Issue3455 { + + @Test + public void shouldEscapeJavaSpecialCharacters() throws Exception { + new ProcessorRunner(new C3455()) + .withRouter( + (app, source) -> { + assertTrue(source.toString().contains("\"/\\\"path/required\\\"-string-param\"")); + assertTrue(source.toString().contains("\"test\\\"ttttt\"")); + assertTrue(source.toString().contains("\"value\\\"\"")); + }); + } +}