Hello,

We recently refactored our large avro schema into separate schemas to make them 
more composable, since many of them get incorporated into other objects.  We 
were glad to see that the avro-maven-plugin allows this composable model rather 
than having to do one large schema with everything embedded.

However, we have hit a problem - the Parser cannot always resolve the 
cross-references.  I upgraded to avro-1.7.7 (both the core avro and the 
avro-maven-plugin project), but that does not solve the issue.

The problem is that names/schemas are not always resolved.  Worse, we see 
different behavior on Windows vs. Linux.  Below I show a set up with a dummy 
schema that works on Windows 7, but fails on Linux (tested on Centos 6 and 
Ubuntu 14.04).  We also have a more complicated schema with many objects which 
have a number of cross references (but not circular ones) that fails on both 
Windows and Linux.

Is this behavior a defect?  Should the Schema.Parser be able to resolve these 
cross-dependencies?

A larger question is why we need to put things in two directories (top level 
and "imports").  Couldn't the Parser be made to resolve references of things 
when they are all in the same directory?



Here is a detailed example - again this one works on Windows but fails on Linux:

u070072@TST imports$ tree
imports
├── pom.xml   (1.4 KiB)
├── src
│   ├── main
│      ├── java
│         ├── quux00
│            ├── App.java   (182 B)
│      ├── resources
│         ├── avro
│            ├── Top.avsc   (473 B)
│            ├── import
│               ├── Bottom.avsc   (239 B)
│               ├── Foo.avsc   (307 B)
│               ├── Middle.avsc   (393 B)


$ mvn -X generate-sources
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.786 s
[INFO] Finished at: 2014-08-04T15:06:02-05:00
[INFO] Final Memory: 19M/843M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.avro:avro-maven-plugin:1.7.7:schema 
(default) on project imports: Execution default of goal 
org.apache.avro:avro-maven-plugin:1.7.7:schema failed: Undefined name: "Bottom" 
-> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal 
org.apache.avro:avro-maven-plugin:1.7.7:schema (default) on project imports: 
Execution default of goal org.apache.avro:avro-maven-plugin:1.7.7:schema 
failed: Undefined name: "Bottom"
        at 
org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:224)
        at 
org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
        at 
org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
        at 
org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:108)
        at 
org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:76)
        at 
org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
        at 
org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:116)
        at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:361)
        at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:155)
        at org.apache.maven.cli.MavenCli.execute(MavenCli.java:584)
        at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:213)
        at org.apache.maven.cli.MavenCli.main(MavenCli.java:157)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at 
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at 
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at 
org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
        at 
org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
        at 
org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
        at 
org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
Caused by: org.apache.maven.plugin.PluginExecutionException: Execution default 
of goal org.apache.avro:avro-maven-plugin:1.7.7:schema failed: Undefined name: 
"Bottom"
        at 
org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:144)
        at 
org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:208)
        ... 19 more
Caused by: org.apache.avro.SchemaParseException: Undefined name: "Bottom"
        at org.apache.avro.Schema.parse(Schema.java:1162)
        at org.apache.avro.Schema.parse(Schema.java:1272)
        at org.apache.avro.Schema.parse(Schema.java:1203)
        at org.apache.avro.Schema$Parser.parse(Schema.java:965)
        at org.apache.avro.Schema$Parser.parse(Schema.java:932)
        at org.apache.avro.mojo.SchemaMojo.doCompile(SchemaMojo.java:73)
        at 
org.apache.avro.mojo.AbstractAvroMojo.compileFiles(AbstractAvroMojo.java:216)
        at 
org.apache.avro.mojo.AbstractAvroMojo.execute(AbstractAvroMojo.java:154)
        at 
org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:133)
        ... 20 more


Here are the schema sections:

$ cat src/main/resources/avro/Top.avsc
{
  "namespace": "quux00.avro",
  "type": "record",
  "name": "Top",
  "fields": [
    {"name": "TopId",     "type": ["null", "string"], "default": null},
    {"name": "TopCode",   "type": ["null", "string"], "default": null},
    {"name": "Middles",   "type": ["null", {"type": "array", "items": 
"Middle"}], "default": null},
    {"name": "Bottom",    "type": ["null", "Bottom"], "default": null},
    {"name": "AFoo",      "type": ["null", "Foo"], "default": null}
  ]
}

$ cat src/main/resources/avro/import/Middle.avsc
{
  "namespace": "quux00.avro",
  "type": "record",
  "name": "Middle",
  "fields": [
    {"name": "Bottom",      "type": ["null", "Bottom"], "default": null},
    {"name": "MiddleId",    "type": ["null", "string"], "default": null},
    {"name": "MiddleCode",  "type": ["null", "string"], "default": null},
    {"name": "MyFoo",       "type": ["null", "Foo"],    "default": null}
  ]
}

$ cat src/main/resources/avro/import/Foo.avsc
{
  "namespace": "quux00.avro",
  "type": "record",
  "name": "Foo",
  "fields": [
    {"name": "FooId",      "type": ["null", "string"], "default": null},
    {"name": "FooCode",    "type": ["null", "string"], "default": null},
    {"name": "BottomObj",  "type": ["null", "Bottom"], "default": null}
  ]
}

$ cat src/main/resources/avro/import/Bottom.avsc
{
  "namespace": "quux00.avro",
  "type": "record",
  "name": "Bottom",
  "fields": [
    {"name": "BottomId",    "type": ["null", "string"], "default": null},
    {"name": "BottomCode",  "type": ["null", "string"], "default": null}
  ]
}


And the pom:

$ cat pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
  <modelVersion>4.0.0</modelVersion>
  <groupId>quux00</groupId>
  <artifactId>imports</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>imports</name>
  <url>http://maven.apache.org</url>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.avro</groupId>
        <artifactId>avro-maven-plugin</artifactId>
        <version>1.7.7</version>
        <executions>
          <execution>
            <phase>generate-sources</phase>
            <goals>
              <goal>schema</goal>
            </goals>
            <configuration>
              
<sourceDirectory>${project.basedir}/src/main/resources/avro/</sourceDirectory>
              
<outputDirectory>${project.basedir}/src/main/java/</outputDirectory>
              <imports>
                <import>${basedir}/src/main/resources/avro/import</import>
              </imports>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>org.apache.avro</groupId>
      <artifactId>avro</artifactId>
      <version>1.7.7</version>
    </dependency>
  </dependencies>
</project>




Finally, this doesn't seem to be an issue with the avro-maven-plugin.  I see 
the same behavior with the avro-tools jar.  It works on Windows:

$ ls input/
Bottom.avsc  Foo.avsc  Middle.avsc  Top.avsc

$ java -jar ~/bin/avro-tools-1.7.6.jar compile schema input/ out/
Input files to compile:
  input\Bottom.avsc
  input\Dog.avsc
  input\Middle.avsc
  input\Top.avsc

$ tree out/
out
├── quux00
│   ├── avro
│      ├── Bottom.java   (6.4 KiB)
│      ├── Foo.java   (8.1 KiB)
│      ├── Middle.java   (10.1 KiB)
│      ├── Top.java   (12.0 KiB)



but fails on Linux:

$ java -jar ~/bin/avro-tools-1.7.6.jar compile schema input/ out/
Input files to compile:
  input/Foo.avsc
  input/Top.avsc
  input/Middle.avsc
  input/Bottom.avsc
Exception in thread "main" org.apache.avro.SchemaParseException: Undefined 
name: "Bottom"
        at org.apache.avro.Schema.parse(Schema.java:1078)
        at org.apache.avro.Schema.parse(Schema.java:1188)
        at org.apache.avro.Schema.parse(Schema.java:1119)
        at org.apache.avro.Schema$Parser.parse(Schema.java:953)
        at org.apache.avro.Schema$Parser.parse(Schema.java:922)
        at 
org.apache.avro.tool.SpecificCompilerTool.run(SpecificCompilerTool.java:73)
        at org.apache.avro.tool.Main.run(Main.java:84)
        at org.apache.avro.tool.Main.main(Main.java:73)





Thank you,
Michael

Reply via email to