2

I have an annotation processor that I need to give some configuration to tell it a few details about how I want it to generate source code. I spent a good deal of time trying to understand why the file was sitting in target/classes after the build, but I was getting an exception during annotation processing stating that the file did not, in fact, exist.

After much digging I finally figured out why the file (stored in src/main/resources/config) isn't getting copied over to target/classes/config for my annotation processor to read - generate-sources happens before process-resources in the build lifecycle, so the file isn't getting copied over in time for the annotation processor to see it during its run. (maven build lifecycle reference: http://maven.apache.org/ref/3.2.2/maven-core/lifecycles.html)

Here's a high level overview of what I'm trying to do:

I have a jar that I've built that processes annotations and generates interface classes from the information in the annotations to base a client api off of. The idea is that including that jar as a compile-time dependency should automatically generate this code for any project that uses these annotations (with as little-as-possible additional configuration in the client project's pom.xml).

How do I go about either:

  1. Getting (at a minimum) the config.xml portion of process-resources to happen before generate-sources
  2. Adding the file to the classpath of the annotation processor in some other way (we don't need this file in the output archive, so this might be better)
  3. I am also open to other (clean) ways of getting configuration information into the annotation processor if there is a better way that I haven't thought of

I would prefer not to write a whole maven plugin for this if possible.

Edit: Here are the relevant parts of the <build> portion of my client pom per request:

<build>
    <finalName>OurApp</finalName>
    <resources>
        <resource>
            <!-- My config.xml file is located here -->
            <directory>src/main/resources</directory>
        </resource>
        <resource>
            <directory>src/main/webapp</directory>
            <includes>
                <include>*.*</include>
            </includes>
            <excludes><exclude>${project.build.directory}/generated-sources/**</exclude></excludes>
        </resource>
    </resources>
    <plugins>
        <!-- Omit Annotation Processor lib from the compilation phase because the code generated is destined for another, separate jar -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven-compiler-plugin.version}</version>
            <executions>
              <execution>
                <id>annotation-processing</id>
                <phase>generate-sources</phase>
                <goals>
                  <goal>compile</goal>
                </goals>
                <configuration>
                  <proc>only</proc>
                </configuration>
              </execution>
              <!-- Compile the rest of the code in the normal compile phase -->
              <execution>
                <id>compile-without-generated-source</id>
                <phase>compile</phase>
                <goals>
                  <goal>compile</goal>
                </goals>
                <configuration>
                  <excludes><exclude>${project.build.directory}/generated-sources/**</exclude></excludes>
                  <proc>none</proc>
                  <!-- http://jira.codehaus.org/browse/MCOMPILER-230 because this doesn't
                       work in the opposite direction (setting failOnError in the other execution 
                       and leaving the default top-level value alone) -->
                  <failOnError>true</failOnError>
                </configuration>
              </execution>
            </executions>
            <configuration>
                <source>${java.version}</source>
                <target>${java.version}</target>
                <proc>only</proc>
                <failOnError>false</failOnError>
            </configuration>
        </plugin>
        <!-- package generated client into its own SOURCE jar -->
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.4.1</version>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>generated-client-source</descriptorRef>
                </descriptorRefs>
            </configuration>
            <dependencies>
                <dependency>
                    <groupId>com.package</groupId>
                    <artifactId>our-api</artifactId>
                    <version>${our-api.version}</version>
                </dependency>
            </dependencies>
            <executions>
                <execution>
                    <id>client-source</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
khmarbaise
  • 92,914
  • 28
  • 189
  • 235
StormeHawke
  • 5,987
  • 5
  • 45
  • 73
  • Show you pom file otherwise it's hard to guess what's going wrong? – khmarbaise Sep 03 '14 at 14:33
  • See edits, added relevant portions of pom.xml and some other documentation – StormeHawke Sep 03 '14 at 15:06
  • If i understand your request correct you have a part which is generated and an other part which is build as usual. In such cases you should make a separate module with your generated code and a second module which contains the usual part. The consequence of such a thing is to create a multi module build. This makes life easier. Apart from that why do you add things which are already default like `src/main/resources` folder? `src/main/webapp` should never be a part of the resources so you have a war packaging combined with several other things. You are violating separation of concerns. – khmarbaise Sep 04 '14 at 07:44
  • As explained in the question, the code generation phase (`generate-sources`) comes before the resources are copied (`process-resources`). I need a resource in the `generate-sources` phase http://maven.apache.org/ref/3.2.2/maven-core/lifecycles.html – StormeHawke Sep 04 '14 at 12:55
  • If the resource is only copied (and not generated or altered), couldn't you just access it directly in `src/main/resources/config`? The annotation processor should have access to resources via its Filer. – kapex Sep 08 '14 at 11:53

1 Answers1

1

So since this file is only needed at compile time, and since any attempt to draw it directly from the classpath was failing miserably, I decided to plop it in the project root, and add a compiler argument in Maven to point to the file.

  <compilerArgs>
      <compilerArg>-AconfigFilePath=${project.basedir}/config.xml</compilerArg>
  </compilerArgs>

Not quite as elegant as getting it off the classpath automatically, but still better than supplying all the configuration elements as separate properties.

Thanks for the suggestions

StormeHawke
  • 5,987
  • 5
  • 45
  • 73