From ca41764fd52b35cbc971bb3d1f3a3410e7c8af1a Mon Sep 17 00:00:00 2001 From: Oscar Westra van Holthe - Kind Date: Fri, 6 Sep 2024 17:16:49 +0200 Subject: [PATCH 1/7] AVRO-4053: Improve consistency in javadoc comments --- .../compiler/specific/SpecificCompiler.java | 6 ++-- .../specific/templates/java/classic/enum.vm | 4 +-- .../specific/templates/java/classic/fixed.vm | 4 +-- .../templates/java/classic/protocol.vm | 8 ++--- .../specific/templates/java/classic/record.vm | 32 +++++++++---------- .../src/test/resources/simple_record.avsc | 5 +-- .../specific/TestSpecificCompiler.java | 2 +- 7 files changed, 31 insertions(+), 30 deletions(-) diff --git a/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java b/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java index 53675f4a01b..d5ae4507cad 100644 --- a/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java +++ b/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java @@ -1024,7 +1024,7 @@ public String[] javaAnnotations(JsonProperties props) { /** * Utility for template use. Takes a (potentially overly long) string and splits - * it into a quoted, comma-separted sequence of escaped strings. + * it into a quoted, comma-separated sequence of escaped strings. * * @param s The string to split * @return A sequence of quoted, comma-separated, escaped strings @@ -1036,7 +1036,7 @@ public String javaSplit(String s) throws IOException { if (i != 0) b.append("\",\""); // insert quote-comma-quote String chunk = s.substring(i, Math.min(s.length(), i + maxStringChars)); - b.append(javaEscape(chunk)); // escape chunks + b.append(escapeForJavaString(chunk)); // escape chunks } b.append("\""); // final quote return b.toString(); @@ -1045,7 +1045,7 @@ public String javaSplit(String s) throws IOException { /** * Utility for template use. Escapes quotes and backslashes. */ - public static String javaEscape(String o) { + public static String escapeForJavaString(String o) { return o.replace("\\", "\\\\").replace("\"", "\\\""); } diff --git a/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/enum.vm b/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/enum.vm index c15b7ecd124..1e34e85610a 100644 --- a/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/enum.vm +++ b/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/enum.vm @@ -19,7 +19,7 @@ package $this.mangle($schema.getNamespace()); #end #if ($schema.getDoc()) -/** $schema.getDoc() */ +/** $this.escapeForJavadoc($schema.getDoc()) */ #end #foreach ($annotation in $this.javaAnnotations($schema)) @$annotation @@ -28,7 +28,7 @@ package $this.mangle($schema.getNamespace()); public enum ${this.mangleTypeIdentifier($schema.getName())} implements org.apache.avro.generic.GenericEnumSymbol<${this.mangleTypeIdentifier($schema.getName())}> { #foreach ($symbol in ${schema.getEnumSymbols()})${this.mangle($symbol)}#if ($foreach.hasNext), #end#end ; - public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("${this.javaEscape($schema.toString())}"); + public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("${this.escapeForJavaString($schema.toString())}"); public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; } @Override diff --git a/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/fixed.vm b/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/fixed.vm index dbbef6ffb12..0f305af3190 100644 --- a/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/fixed.vm +++ b/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/fixed.vm @@ -19,7 +19,7 @@ package $this.mangle($schema.getNamespace()); #end #if ($schema.getDoc()) -/** $schema.getDoc() */ +/** $this.escapeForJavadoc($schema.getDoc()) */ #end #foreach ($annotation in $this.javaAnnotations($schema)) @$annotation @@ -28,7 +28,7 @@ package $this.mangle($schema.getNamespace()); @org.apache.avro.specific.AvroGenerated public class ${this.mangleTypeIdentifier($schema.getName())} extends org.apache.avro.specific.SpecificFixed { private static final long serialVersionUID = ${this.fingerprint64($schema)}L; - public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("${this.javaEscape($schema.toString())}"); + public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("${this.escapeForJavaString($schema.toString())}"); public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; } public org.apache.avro.Schema getSchema() { return SCHEMA$; } diff --git a/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/protocol.vm b/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/protocol.vm index f9a4d1aeccd..46ac443ac8d 100644 --- a/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/protocol.vm +++ b/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/protocol.vm @@ -20,7 +20,7 @@ package $this.mangle($protocol.getNamespace()); #end #if ($protocol.getDoc()) -/** $protocol.getDoc() */ +/** $this.escapeForJavadoc($protocol.getDoc()) */ #end #foreach ($annotation in $this.javaAnnotations($protocol)) @$annotation @@ -37,7 +37,7 @@ public interface $this.mangleTypeIdentifier($protocol.getName()) { * $this.escapeForJavadoc($message.getDoc()) #end #foreach ($p in $message.getRequest().getFields())## -#if ($p.doc()) * @param ${this.mangle($p.name())} $p.doc() +#if ($p.doc()) * @param ${this.mangle($p.name())} $this.escapeForJavadoc($p.doc()) #end #end */ @@ -62,7 +62,7 @@ ${this.mangle($error.getFullName())}## ## Generate nested callback API #if ($protocol.getDoc()) - /** $protocol.getDoc() */ + /** $this.escapeForJavadoc($protocol.getDoc()) */ #end @org.apache.avro.specific.AvroGenerated public interface Callback extends $this.mangleTypeIdentifier($protocol.getName()) { @@ -78,7 +78,7 @@ ${this.mangle($error.getFullName())}## * $this.escapeForJavadoc($message.getDoc()) #end #foreach ($p in $message.getRequest().getFields())## -#if ($p.doc()) * @param ${this.mangle($p.name())} $p.doc() +#if ($p.doc()) * @param ${this.mangle($p.name())} $this.escapeForJavadoc($p.doc()) #end #end * @throws java.io.IOException The async call could not be completed. diff --git a/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/record.vm b/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/record.vm index ec1e6c3ca7a..eef50ec7208 100755 --- a/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/record.vm +++ b/lang/java/compiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/record.vm @@ -29,7 +29,7 @@ import org.apache.avro.message.SchemaStore; #if (${this.gettersReturnOptional} || ${this.createOptionalGetters})import java.util.Optional;#end #if ($schema.getDoc()) -/** $schema.getDoc() */ +/** $this.escapeForJavadoc($schema.getDoc()) */ #end #foreach ($annotation in $this.javaAnnotations($schema)) @$annotation @@ -116,7 +116,7 @@ public class ${this.mangleTypeIdentifier($schema.getName())} extends ${this.getS #foreach ($field in $schema.getFields()) #if ($field.doc()) - /** $field.doc() */ + /** $this.escapeForJavadoc($field.doc()) */ #end #foreach ($annotation in $this.javaAnnotations($field)) @$annotation @@ -155,7 +155,7 @@ public class ${this.mangleTypeIdentifier($schema.getName())} extends ${this.getS /** * All-args constructor. #foreach ($field in $schema.getFields()) -#if ($field.doc()) * @param ${this.mangle($field.name())} $field.doc() +#if ($field.doc()) * @param ${this.mangle($field.name())} $this.escapeForJavadoc($field.doc()) #else * @param ${this.mangle($field.name())} The new value for ${field.name()} #end #end @@ -228,7 +228,7 @@ public class ${this.mangleTypeIdentifier($schema.getName())} extends ${this.getS #if (${this.gettersReturnOptional} && (!${this.optionalGettersForNullableFieldsOnly} || ${field.schema().isNullable()})) /** * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field as an Optional<${this.escapeForJavadoc(${this.javaType($field.schema())})}>. -#if ($field.doc()) * $field.doc() +#if ($field.doc()) * $this.escapeForJavadoc($field.doc()) #end * @return The value wrapped in an Optional<${this.escapeForJavadoc(${this.javaType($field.schema())})}>. */ @@ -238,7 +238,7 @@ public class ${this.mangleTypeIdentifier($schema.getName())} extends ${this.getS #else /** * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field. -#if ($field.doc()) * @return $field.doc() +#if ($field.doc()) * @return $this.escapeForJavadoc($field.doc()) #else * @return The value of the '${this.mangle($field.name(), $schema.isError())}' field. #end */ @@ -257,7 +257,7 @@ public class ${this.mangleTypeIdentifier($schema.getName())} extends ${this.getS #if (${this.createOptionalGetters}) /** * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field as an Optional<${this.escapeForJavadoc(${this.javaType($field.schema())})}>. -#if ($field.doc()) * $field.doc() +#if ($field.doc()) * $this.escapeForJavadoc($field.doc()) #end * @return The value wrapped in an Optional<${this.escapeForJavadoc(${this.javaType($field.schema())})}>. */ @@ -269,7 +269,7 @@ public class ${this.mangleTypeIdentifier($schema.getName())} extends ${this.getS #if ($this.createSetters) /** * Sets the value of the '${this.mangle($field.name(), $schema.isError())}' field. -#if ($field.doc()) * $field.doc() +#if ($field.doc()) * $this.escapeForJavadoc($field.doc()) #end * @param value the value to set. */ @@ -323,7 +323,7 @@ public class ${this.mangleTypeIdentifier($schema.getName())} extends ${this.getS #foreach ($field in $schema.getFields()) #if ($field.doc()) - /** $field.doc() */ + /** $this.escapeForJavadoc($field.doc()) */ #end private ${this.javaUnbox($field.schema(), false)} ${this.mangle($field.name(), $schema.isError())}; #if (${this.hasBuilder($field.schema())}) @@ -402,7 +402,7 @@ public class ${this.mangleTypeIdentifier($schema.getName())} extends ${this.getS #foreach ($field in $schema.getFields()) /** * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field. -#if ($field.doc()) * $field.doc() +#if ($field.doc()) * $this.escapeForJavadoc($field.doc()) #end * @return The value. */ @@ -413,7 +413,7 @@ public class ${this.mangleTypeIdentifier($schema.getName())} extends ${this.getS #if (${this.createOptionalGetters}) /** * Gets the value of the '${this.mangle($field.name(), $schema.isError())}' field as an Optional<${this.escapeForJavadoc(${this.javaType($field.schema())})}>. -#if ($field.doc()) * $field.doc() +#if ($field.doc()) * $this.escapeForJavadoc($field.doc()) #end * @return The value wrapped in an Optional<${this.escapeForJavadoc(${this.javaType($field.schema())})}>. */ @@ -424,7 +424,7 @@ public class ${this.mangleTypeIdentifier($schema.getName())} extends ${this.getS /** * Sets the value of the '${this.mangle($field.name(), $schema.isError())}' field. -#if ($field.doc()) * $field.doc() +#if ($field.doc()) * $this.escapeForJavadoc($field.doc()) #end * @param value The value of '${this.mangle($field.name(), $schema.isError())}'. * @return This builder. @@ -441,7 +441,7 @@ public class ${this.mangleTypeIdentifier($schema.getName())} extends ${this.getS /** * Checks whether the '${this.mangle($field.name(), $schema.isError())}' field has been set. -#if ($field.doc()) * $field.doc() +#if ($field.doc()) * $this.escapeForJavadoc($field.doc()) #end * @return True if the '${this.mangle($field.name(), $schema.isError())}' field has been set, false otherwise. */ @@ -452,7 +452,7 @@ public class ${this.mangleTypeIdentifier($schema.getName())} extends ${this.getS #if (${this.hasBuilder($field.schema())}) /** * Gets the Builder instance for the '${this.mangle($field.name(), $schema.isError())}' field and creates one if it doesn't exist yet. -#if ($field.doc()) * $field.doc() +#if ($field.doc()) * $this.escapeForJavadoc($field.doc()) #end * @return This builder. */ @@ -469,7 +469,7 @@ public class ${this.mangleTypeIdentifier($schema.getName())} extends ${this.getS /** * Sets the Builder instance for the '${this.mangle($field.name(), $schema.isError())}' field -#if ($field.doc()) * $field.doc() +#if ($field.doc()) * $this.escapeForJavadoc($field.doc()) #end * @param value The builder instance that must be set. * @return This builder. @@ -483,7 +483,7 @@ public class ${this.mangleTypeIdentifier($schema.getName())} extends ${this.getS /** * Checks whether the '${this.mangle($field.name(), $schema.isError())}' field has an active Builder instance -#if ($field.doc()) * $field.doc() +#if ($field.doc()) * $this.escapeForJavadoc($field.doc()) #end * @return True if the '${this.mangle($field.name(), $schema.isError())}' field has an active Builder instance */ @@ -494,7 +494,7 @@ public class ${this.mangleTypeIdentifier($schema.getName())} extends ${this.getS /** * Clears the value of the '${this.mangle($field.name(), $schema.isError())}' field. -#if ($field.doc()) * $field.doc() +#if ($field.doc()) * $this.escapeForJavadoc($field.doc()) #end * @return This builder. */ diff --git a/lang/java/compiler/src/test/resources/simple_record.avsc b/lang/java/compiler/src/test/resources/simple_record.avsc index d78fd17e64e..e6e7cb79564 100644 --- a/lang/java/compiler/src/test/resources/simple_record.avsc +++ b/lang/java/compiler/src/test/resources/simple_record.avsc @@ -1,8 +1,9 @@ { - "type": "record", + "type": "record", "name": "SimpleRecord", + "doc": ",*/\n hoping the compiler won't barf on strange comments\n/*", "fields" : [ {"name": "value", "type": "int"}, {"name": "nullableValue", "type": ["null","int"], "doc" : "doc"} ] -} \ No newline at end of file +} diff --git a/lang/java/ipc/src/test/java/org/apache/avro/compiler/specific/TestSpecificCompiler.java b/lang/java/ipc/src/test/java/org/apache/avro/compiler/specific/TestSpecificCompiler.java index 0af06b9a2b1..c9063bca09d 100644 --- a/lang/java/ipc/src/test/java/org/apache/avro/compiler/specific/TestSpecificCompiler.java +++ b/lang/java/ipc/src/test/java/org/apache/avro/compiler/specific/TestSpecificCompiler.java @@ -70,7 +70,7 @@ public class TestSpecificCompiler { @Test void esc() { - assertEquals("\\\"", SpecificCompiler.javaEscape("\"")); + assertEquals("\\\"", SpecificCompiler.escapeForJavaString("\"")); } @Test From 3dd0954dc85320f9c5d5bb395aa949c4e6666922 Mon Sep 17 00:00:00 2001 From: Oscar Westra van Holthe - Kind Date: Fri, 6 Sep 2024 17:19:44 +0200 Subject: [PATCH 2/7] AVRO-4053: Add test case --- .../compiler/specific/SpecificCompiler.java | 65 ++++++++----- .../specific/TestSpecificCompiler.java | 95 ++++++++++++++----- 2 files changed, 111 insertions(+), 49 deletions(-) diff --git a/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java b/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java index d5ae4507cad..55530455840 100644 --- a/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java +++ b/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java @@ -17,6 +17,27 @@ */ package org.apache.avro.compiler.specific; +import org.apache.avro.Conversion; +import org.apache.avro.Conversions; +import org.apache.avro.JsonProperties; +import org.apache.avro.LogicalType; +import org.apache.avro.LogicalTypes; +import org.apache.avro.Protocol; +import org.apache.avro.Protocol.Message; +import org.apache.avro.Schema; +import org.apache.avro.Schema.Field; +import org.apache.avro.SchemaNormalization; +import org.apache.avro.SchemaParser; +import org.apache.avro.data.TimeConversions; +import org.apache.avro.generic.GenericData; +import org.apache.avro.generic.GenericData.StringType; +import org.apache.avro.specific.SpecificData; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -36,30 +57,10 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.avro.Conversion; -import org.apache.avro.Conversions; -import org.apache.avro.JsonProperties; -import org.apache.avro.LogicalType; -import org.apache.avro.LogicalTypes; -import org.apache.avro.Protocol; -import org.apache.avro.Protocol.Message; -import org.apache.avro.Schema; -import org.apache.avro.Schema.Field; -import org.apache.avro.SchemaNormalization; -import org.apache.avro.SchemaParser; -import org.apache.avro.data.TimeConversions; -import org.apache.avro.generic.GenericData; -import org.apache.avro.generic.GenericData.StringType; -import org.apache.avro.specific.SpecificData; -import org.apache.velocity.Template; -import org.apache.velocity.VelocityContext; -import org.apache.velocity.app.VelocityEngine; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import static java.nio.charset.StandardCharsets.UTF_8; /** @@ -1004,21 +1005,35 @@ public String conversionInstance(Schema schema) { */ public String[] javaAnnotations(JsonProperties props) { final Object value = props.getObjectProp("javaAnnotation"); - if (value == null) - return new String[0]; - if (value instanceof String) + if (value instanceof String && isValidAsAnnotation((String) value)) return new String[] { value.toString() }; if (value instanceof List) { final List list = (List) value; final List annots = new ArrayList<>(list.size()); for (Object o : list) { - annots.add(o.toString()); + if (isValidAsAnnotation(o.toString())) + annots.add(o.toString()); } return annots.toArray(new String[0]); } return new String[0]; } + private static final String PATTERN_IDENTIFIER = "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*"; + private static final String PATTERN_STRING = "\"(?:\\\\[\\\\\"ntfb]|(?\\n/*\",\n" + " \"types\" : [\n" + + " {\"type\": \"fixed\", \"name\": \"Hash\", \"size\": 16, \"doc\": \"*/\\nTest escaping \\n/*\"" + + "},\n" + + " {\"type\": \"enum\", \"name\": \"Status\", \"symbols\": [\"ON\", \"OFF\"], \"doc\": \"*/\\nTest escaping \\n/*\"},\n" + + " " + " {\"type\": \"record\", \"name\": \"Message\", \"fields\" : [\n" + + " {\"name\": \"content\", \"type\": \"string\", \"doc\": \"*/\\nTest escaping \\n/*\"},\n" + + " {\"name\": \"status\", \"type\": \"Status\", \"doc\": \"*/\\nTest escaping \\n/*\"},\n" + + " {\"name\": \"signature\", \"type\": \"Hash\", \"doc\": \"*/\\nTest escaping \\n/*\"}\n" + + " ]}\n" + " ],\n" + " \"messages\" : {\n" + " \"echo\": {\"request\": [" + + "{\"name\": \"msg\", \"type\": \"Message\"}" + + "], \"response\": \"Message\", \"doc\": \"*/\\nTest escaping \\n/*\"}\n" + " },\n" + + " \"javaAnnotation\": [\n" + " \"Deprecated(forRemoval = true, since = \\\"forever\\\")\",\n" + + " \"SuppressWarnings(\\\"ALL\\\")\",\n" + " \"SuppressWarnings(\\\"CodeInjection\\\")/*\",\n" + + " \" This is inside a comment as each line is prefixed with @\",\n" + + " \" and the next bit is really dangerous... */ static { System.exit(); }\"\n" + " ]\n" + "}"; + Collection outputs = new SpecificCompiler(Protocol.parse(jsonSchema)).compile(); + for (SpecificCompiler.OutputFile outputFile : outputs) { + assertFalse(outputFile.contents.contains("*/\\nTest escaping \\n/*"), "Threats present?"); + + int expectedEscapeCount = countOccurrences(Pattern.compile("Test escaping", Pattern.LITERAL), + outputFile.contents); + int escapedJavaDocCount = countOccurrences(Pattern.compile("\\*/\\s*Test escaping <threats>\\s*/\\*"), + outputFile.contents); + // noinspection RegExpRedundantEscape + int escapedDocStringCount = countOccurrences( + Pattern.compile("\\\"doc\\\":\\\"*/\\\\nTest escaping \\\\n/*\\\"", Pattern.LITERAL), + outputFile.contents); + assertEquals(expectedEscapeCount, escapedJavaDocCount + escapedDocStringCount, + "Escaped threats in " + outputFile.path); + + assertFalse(Pattern.compile("\\{ System.exit\\(\\); }(?!\\\\\")").matcher(outputFile.contents).find(), + "Code injection present? " + outputFile.contents); + } + } + + private int countOccurrences(Pattern pattern, String textToSearch) { + int count = 0; + for (Matcher matcher = pattern.matcher(textToSearch); matcher.find();) { + count++; + } + return count; + } } From ae42e40d3bd0dd9ff6bab0498e3272416a0ff4fd Mon Sep 17 00:00:00 2001 From: Oscar Westra van Holthe - Kind Date: Fri, 6 Sep 2024 21:39:22 +0200 Subject: [PATCH 3/7] AVRO-4053: rename test --- .../org/apache/avro/compiler/specific/TestSpecificCompiler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/java/compiler/src/test/java/org/apache/avro/compiler/specific/TestSpecificCompiler.java b/lang/java/compiler/src/test/java/org/apache/avro/compiler/specific/TestSpecificCompiler.java index 6fe45b0d96e..d1338590b78 100644 --- a/lang/java/compiler/src/test/java/org/apache/avro/compiler/specific/TestSpecificCompiler.java +++ b/lang/java/compiler/src/test/java/org/apache/avro/compiler/specific/TestSpecificCompiler.java @@ -993,7 +993,7 @@ void fieldWithUnderscore_avro3826() { } @Test - void docsAreEscaped_avro() { + void docsAreEscaped_avro4053() { String jsonSchema = "{\n" + " \"protocol\": \"DummyProtocol\",\n" + " \"doc\": \"*/\\nTest escaping \\n/*\",\n" + " \"types\" : [\n" + " {\"type\": \"fixed\", \"name\": \"Hash\", \"size\": 16, \"doc\": \"*/\\nTest escaping \\n/*\"" From 256976f58970f9e249ebe5632f39f648637a0607 Mon Sep 17 00:00:00 2001 From: Oscar Westra van Holthe - Kind Date: Fri, 6 Sep 2024 21:57:07 +0200 Subject: [PATCH 4/7] AVRO-4053: Fix omission --- .../org/apache/avro/compiler/specific/SpecificCompiler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java b/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java index 55530455840..a5728cb02b7 100644 --- a/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java +++ b/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java @@ -1019,7 +1019,8 @@ public String[] javaAnnotations(JsonProperties props) { return new String[0]; } - private static final String PATTERN_IDENTIFIER = "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*"; + private static final String PATTERN_IDENTIFIER_PART = "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*"; + private static final String PATTERN_IDENTIFIER = String.format("(?:%s(?:\\.%s)*)", PATTERN_IDENTIFIER_PART, PATTERN_IDENTIFIER_PART); private static final String PATTERN_STRING = "\"(?:\\\\[\\\\\"ntfb]|(? Date: Fri, 6 Sep 2024 21:59:14 +0200 Subject: [PATCH 5/7] AVRO-4053: spotless --- .../org/apache/avro/compiler/specific/SpecificCompiler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java b/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java index a5728cb02b7..8f2bcf82253 100644 --- a/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java +++ b/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java @@ -1020,7 +1020,8 @@ public String[] javaAnnotations(JsonProperties props) { } private static final String PATTERN_IDENTIFIER_PART = "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*"; - private static final String PATTERN_IDENTIFIER = String.format("(?:%s(?:\\.%s)*)", PATTERN_IDENTIFIER_PART, PATTERN_IDENTIFIER_PART); + private static final String PATTERN_IDENTIFIER = String.format("(?:%s(?:\\.%s)*)", PATTERN_IDENTIFIER_PART, + PATTERN_IDENTIFIER_PART); private static final String PATTERN_STRING = "\"(?:\\\\[\\\\\"ntfb]|(? Date: Tue, 24 Sep 2024 13:36:09 +0200 Subject: [PATCH 6/7] AVRO-4053: Restore old name in public API --- .../avro/compiler/specific/SpecificCompiler.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java b/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java index 8f2bcf82253..2fd3103a4ef 100644 --- a/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java +++ b/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java @@ -1066,6 +1066,16 @@ public static String escapeForJavaString(String o) { return o.replace("\\", "\\\\").replace("\"", "\\\""); } + /** + * Utility for template use (previous name). Escapes quotes and backslashes. + * + * @deprecated Use {@link #escapeForJavaString(String)} instead + */ + @Deprecated(since = "1.12.1", forRemoval = true) + public static String javaEscape(String o) { + return escapeForJavaString(o); + } + /** * Utility for template use. Escapes comment end with HTML entities. */ From e21a94c5729670432e7776e1184a458f8748c6f1 Mon Sep 17 00:00:00 2001 From: Oscar Westra van Holthe - Kind Date: Fri, 27 Sep 2024 10:13:55 +0200 Subject: [PATCH 7/7] AVRO-4053: Static imports on top --- .../compiler/specific/SpecificCompiler.java | 4 ++-- .../specific/TestSpecificCompiler.java | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java b/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java index 2fd3103a4ef..cad00e943f2 100644 --- a/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java +++ b/lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java @@ -17,6 +17,8 @@ */ package org.apache.avro.compiler.specific; +import static java.nio.charset.StandardCharsets.UTF_8; + import org.apache.avro.Conversion; import org.apache.avro.Conversions; import org.apache.avro.JsonProperties; @@ -61,8 +63,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static java.nio.charset.StandardCharsets.UTF_8; - /** * Generate specific Java interfaces and classes for protocols and schemas. *

diff --git a/lang/java/compiler/src/test/java/org/apache/avro/compiler/specific/TestSpecificCompiler.java b/lang/java/compiler/src/test/java/org/apache/avro/compiler/specific/TestSpecificCompiler.java index d1338590b78..19d63d033c7 100644 --- a/lang/java/compiler/src/test/java/org/apache/avro/compiler/specific/TestSpecificCompiler.java +++ b/lang/java/compiler/src/test/java/org/apache/avro/compiler/specific/TestSpecificCompiler.java @@ -17,6 +17,15 @@ */ package org.apache.avro.compiler.specific; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import org.apache.avro.AvroTypeException; import org.apache.avro.LogicalType; import org.apache.avro.LogicalTypes; @@ -54,15 +63,6 @@ import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.hasItem; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - public class TestSpecificCompiler { private static final Logger LOG = LoggerFactory.getLogger(TestSpecificCompiler.class);