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 47ff7510640..e3f751037f3 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 @@ -122,6 +122,7 @@ void addLogicalTypeConversions(SpecificData specificData) { private boolean createAllArgsConstructor = true; private String outputCharacterEncoding; private boolean enableDecimalLogicalType = false; + private boolean modifySchema = true; private String suffix = ".java"; private List additionalVelocityTools = Collections.emptyList(); @@ -560,7 +561,9 @@ protected void validateRecordForCompilation(Schema record) { } OutputFile compile(Schema schema) { - schema = addStringType(schema); // annotate schema as needed + if (modifySchema) { + schema = addStringType(schema); // annotate schema as needed + } String output = ""; VelocityContext context = new VelocityContext(); context.put("this", this); @@ -1213,4 +1216,16 @@ public static void main(String[] args) throws Exception { public void setOutputCharacterEncoding(String outputCharacterEncoding) { this.outputCharacterEncoding = outputCharacterEncoding; } + + /** + * Sets whether the input schema is modified with Java specific logical String + * type with field "avro.java.string". Modifications only occur if stringType is + * set to StringType.String AND modifySchema is true. + * + * @param modifySchema Whether to modify schemas with logical type (defaults to + * true) + */ + public void setModifySchema(boolean modifySchema) { + this.modifySchema = modifySchema; + } } 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 0bb0d5f6ddd..691ce2ae56a 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 @@ -77,6 +77,10 @@ public void setUp() { private File src = new File("src/test/resources/simple_record.avsc"); + // Need a test file with a string, modifying above breaks some tests that make + // file assumptions + private File srcWithString = new File("src/test/resources/simple_record_with_string.avsc"); + static void assertCompilesWithJavaCompiler(File dstDir, Collection outputs) throws IOException { assertCompilesWithJavaCompiler(dstDir, outputs, false); @@ -136,8 +140,12 @@ private static Schema createSampleRecordSchema(int numStringFields, int numDoubl } private SpecificCompiler createCompiler() throws IOException { + return createCompiler(this.src); + } + + private SpecificCompiler createCompiler(File sourceSchema) throws IOException { Schema.Parser parser = new Schema.Parser(); - Schema schema = parser.parse(this.src); + Schema schema = parser.parse(sourceSchema); SpecificCompiler compiler = new SpecificCompiler(schema); String velocityTemplateDir = "src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/"; compiler.setTemplateDir(velocityTemplateDir); @@ -320,6 +328,33 @@ public void testSettingOutputCharacterEncoding() throws Exception { new String(fileInDefaultEncoding), equalTo(new String(fileInDifferentEncoding, differentEncoding))); } + @Test + public void testSettingDoNotModifySchema() throws Exception { + SpecificCompiler compiler = createCompiler(this.srcWithString); + compiler.setStringType(StringType.String); // This is only type in which schema is modified + // Generated file with Java types (default) + compiler.compileToDestination(this.srcWithString, this.OUTPUT_DIR.getRoot()); + byte[] fileWithDefaultModification = new byte[(int) this.outputFile.length()]; + FileInputStream is = new FileInputStream(this.outputFile); + is.read(fileWithDefaultModification); + is.close(); // close input stream otherwise delete might fail + if (!this.outputFile.delete()) { + throw new IllegalStateException("unable to delete " + this.outputFile); // delete otherwise compiler might not + // overwrite because src timestamp hasn't + // changed. + } + // Generate file without Java specific type (should be less bytes) + compiler.setModifySchema(false); + compiler.compileToDestination(this.srcWithString, this.OUTPUT_DIR.getRoot()); + byte[] fileWithoutModification = new byte[(int) this.outputFile.length()]; + is = new FileInputStream(this.outputFile); + is.read(fileWithoutModification); + is.close(); + // Compare as bytes + assertThat("Generated file should contain different bytes", fileWithDefaultModification, + not(equalTo(fileWithoutModification))); + } + @Test public void testJavaTypeWithDecimalLogicalTypeEnabled() throws Exception { SpecificCompiler compiler = createCompiler(); diff --git a/lang/java/compiler/src/test/resources/simple_record_with_string.avsc b/lang/java/compiler/src/test/resources/simple_record_with_string.avsc new file mode 100644 index 00000000000..7585747e5ee --- /dev/null +++ b/lang/java/compiler/src/test/resources/simple_record_with_string.avsc @@ -0,0 +1,7 @@ +{ + "type": "record", + "name": "SimpleRecord", + "fields" : [ + {"name": "value", "type": "string"} + ] +} diff --git a/lang/java/tools/src/main/java/org/apache/avro/tool/SpecificCompilerTool.java b/lang/java/tools/src/main/java/org/apache/avro/tool/SpecificCompilerTool.java index 04eb5466bac..a52f5738dfa 100644 --- a/lang/java/tools/src/main/java/org/apache/avro/tool/SpecificCompilerTool.java +++ b/lang/java/tools/src/main/java/org/apache/avro/tool/SpecificCompilerTool.java @@ -48,14 +48,15 @@ public class SpecificCompilerTool implements Tool { @Override public int run(InputStream in, PrintStream out, PrintStream err, List origArgs) throws Exception { if (origArgs.size() < 3) { - System.err - .println("Usage: [-encoding ] [-string] [-bigDecimal] [-fieldVisibility ] " - + "[-noSetters] [-addExtraOptionalGetters] [-optionalGetters ] " - + "[-templateDir ] (schema|protocol) input... outputdir"); + System.err.println("Usage: [-encoding ] [-string] [-doNotModifySchema] [-bigDecimal] " + + "[-fieldVisibility ] " + + "[-noSetters] [-addExtraOptionalGetters] [-optionalGetters ] " + + "[-templateDir ] (schema|protocol) input... outputdir"); System.err.println(" input - input files or directories"); System.err.println(" outputdir - directory to write generated java"); System.err.println(" -encoding - set the encoding of " + "output file(s)"); System.err.println(" -string - use java.lang.String instead of Utf8"); + System.err.println(" -doNotModifySchema - do not modify schemas as provided"); System.err.println(" -fieldVisibility [private|public] - use either and default private"); System.err.println(" -noSetters - do not generate setters"); System.err @@ -192,6 +193,7 @@ private void executeCompiler(SpecificCompiler compiler, CompilerOptions opts, Fi compiler.setEnableDecimalLogicalType(opts.useLogicalDecimal); opts.encoding.ifPresent(compiler::setOutputCharacterEncoding); opts.fieldVisibility.ifPresent(compiler::setFieldVisibility); + compiler.setModifySchema(!opts.doNotModifySchema); compiler.compileToDestination(src, output); } @@ -268,6 +270,7 @@ private static class CompilerOptions { boolean useLogicalDecimal; boolean createSetters; boolean addExtraOptionalGetters; + boolean doNotModifySchema; Optional optionalGettersType; Optional templateDir; }