Monday, April 26, 2010

Calling javac from Ant Inside Maven Using AntRun

We ran into a situation where we needed to call Ant's javac task to compile code generated by a legacy Ant task as part of a larger build.  This exposed a very confusing feature of Maven: it apparently changes the java.home property to point to the JRE home. This is no problem on Macs but is on Linux.

There are several possible workarounds.  The one that I currently prefer is to exploit the fact that Maven only overrides ${java.home} but not the original ${env.JAVA_HOME}.  So your <javac> task inside the antrun plugin should look like this:

<javac fork="true" executable="${env.JAVA_HOME}/bin/javac" srcdir="${final.src.dir}" destdir="${final.class.dir}">
<classpath refid="maven.dependency.classpath"/>
</javac>
In testing, the fork attribute needed to be set to true, but I don't know why. 

Another workaround is to specify the location of tools.jar in the Antrun plugin's dependencies.  This introduces a second problem: Mac and Linux put the tools.jar classes in different jars.  For Linux, this is just in $JAVA_HOME/lib/tools.jar as you would expect, but Mac embeds these classes in classes.jar, located in $JAVA_HOME/../Classes/classes.jar.  Thus you should use 

   <plugin>
 <artifactId>maven-antrun-plugin</artifactId>
 <dependencies>
             <dependency>
               <groupId>com.sun</groupId>
               <artifactId>tools</artifactId>
               <version>1.5.0</version>
               <scope>system</scope>
               <systemPath>${tools.jar}</systemPath>
             </dependency>
           </dependencies>
 <!-- Remainder of the antrun configuration and execution -->
      </plugin>


Set ${tools.jar} depending on your operating system as described in the preceding paragraph.  Obviously this introduces an undesirable need to either set or detect the operating system of the build.

Perhaps there is some deep reason for Maven to internally overwrite java.home, but I can't guess it.  This really should be cleaned up.