I am trying to run Ant script and getting following error at line:
<javac deprecation="on"
destdir="${prj.build}"
debug="${prj.debug}"
debuglevel="lines,source"
***classpathref="compile.classpath">***
<src path="${prj.src}"/>
Unable to find a javac compiler;
com.sun.tools.javac.Main is not on the classpath.
Perhaps JAVA_HOME does not point to the JDK.
Do you have the JDK installed? The JRE alone is not enough for many ant tasks.
If yes, read the error message: do you have an environment variable named JAVA_HOME, and does it point to the jdk-directory? (This is used by the ant wrapper script to setup the paths right.)
Related
I hope this finds an ANT build master who has some experience running ANT with different JDK versions concurrently!
I have inherited a fairly old set of libraries & ANT build files that currently work under Java 6/7. In attempting to modernize this system to utilize Java 8 or any future JDK upgrades, I've been working on a means of refactoring these build files to work with Java 8.
The current build system has the following characteristic:
Ant 1.7.0 & Java 1.7.0_55
Usage of the deprecated APT tool via ANT APT tasks
Usage of wsgen (jaxws related libraries) via ANT WSGEN tasks (e.g. classname="com.sun.tools.ws.ant.WsGen")
Effectively the build files mix code generation and compilation to create our desired output.
The APT tool was deprecated in Java 1.7, one needs to move to using JAVAC in 1.8 and beyond!
In attempting to replace the usages of APT with JAVAC I found that not only is the tool removed but so are the numerous packages/class/interfaces associated with the APT tool. I've seen this topic discussed here in multiple Q&A's, however most of the proposed solutions were non-starters.
The one suggestion I did find which had promise was to separate the code generation (usages of APT) from the compilation (JAVAC) to reside in different ANT build files. After separating the build file into a "main" build file and a "codegen" build file, this seems to work just fine.
Example:
<property name="apt.output.file" value="codegen.apt.${java.version}.log" /> <!-- A different log file will exist when I run the "main" ant build file using Java 7 vs 8 for comparison purposes. -->
<exec executable="${exec.ant.cmd}" osfamily="unix" failonerror="true" output="${apt.output.file}" >
<arg line="${ant.apt.cmd.line.options}" />
<env key="JAVA_HOME" value="${exec.java.home}"/> <!-- Java 1.7 -->
<env key="ANT_HOME" value="${ant.home.path}"/> <!-- Ant 1.7.0 -->
<env key="PATH" value="${exec.java.home}/bin" /> <!-- Reset PATH to be certain -->
<!-- The various properties are defined in the build file, and would be fairly unsurprising. -->
</exec>
Now that the "codegen" pieces were self-contained, this allows me to:
Run the "main" ANT build file with Java 8.
For the "codegen" pieces, use an EXEC as per above to specify the ANT/JAVA version to do the *.java code generation.
The good news, for those of you in similar situations, is that this seems to work fine for APT. I changed my JAVA_HOME & PATH to point at Java 8, and it seems to work fine (assuming APT is limited to just *.java source generation, no compilation).
Now here's the rub and what I hope someone might have some expertise on. I found that the APT tool was also used to create an ANT build file (wsgen-build.xml). Said file defines the WSGEN task and then uses it a number of times:
<project name="some-wsgen-fragment" default="wsgenall">
<target name="wsgenall">
<taskdef name="wsgen" classname="com.sun.tools.ws.ant.WsGen" >
<classpath>
<pathelement path="${jaxws.home}/lib/jaxws-tools.jar" />
</classpath>
</taskdef>
<echo message="wsgen for SomeWebServiceImpl" />
<wsgen destdir="${classes.server.gen.dir}" sourcedestdir="${something.gen.dir}" sei="com.something.or.other.SomeWebServiceImpl">
<classpath>
<pathelement path="${classes.server.gen.dir}" />
<path refid="classpath.all" />
</classpath>
</wsgen>
... Repeated usages of wsgen exactly as above, with different classes
Similar to the APT tasks, the "main" build file invokes an EXEC to run an "old" ANT with appropriate parameters to invoke this generated build file under the same environment it works under.
Under Java 1.7 & ANT 1.7.0, this works fine.
When I change Java to 1.8, I change the JDK for JAVA_HOME and the "java.target" to 1.8, I get the following mysterious error:
[echo] wsgen for SomeWebServiceImpl
Finding class com.something.or.other.SomeWebServiceImpl
[antcall] Exiting codegen-buildfile.xml.
BUILD FAILED
codegen-buildfile.xml:58: The following error occurred while executing this line:
wsgen-build.xml:9: Requires JDK 5.0 or later. Please download it from http://java.sun.com/j2se/1.5/
at org.apache.tools.ant.ProjectHelper.addLocationToBuildException(ProjectHelper.java:541)
at org.apache.tools.ant.taskdefs.Ant.execute(Ant.java:418)
at org.apache.tools.ant.taskdefs.CallTarget.execute(CallTarget.java:105)
The issue to me "feels" like the following:
Why does an ANT running Java 8 interfere with an ANT running Java 7 and how might this be remedied?
Some Q&A that has lead me to this question:
Have you tried using ANT -v -d for figuring this out?
Yes, I'm generating a log file based on the ${java.version} used for the "main" build file. I generate a file for Java 8 and one for Java 7, and diff the two. There are no environment/property/settings difference between the two (Java 7 vs Java 8) until I hit the error referenced above. There are minor variations in the order classes get loaded, but that is it.
When you change between Java 7 and Java 8, are you making sure that change isn't affecting your EXEC tasks?
The diff of the log files as referenced above verifies this, but when I invoke EXEC the properties in the first example above are effectively hard-coded with the ENV tags being used to ensure the environment variables are also the same regardless of the Java version used in the "main" build file.
Surely there is some environment variable difference causing this issue?
I'm logging a number of variables attempting to diagnose the issue. So far the "codegen" ANT build file has everything the same, regardless if the "main" ANT is run in either Java 7 or 8: ANT_HOME, JAVA_HOME, PATH, ant.version, java.version, java.vm.version, java.class.path, java.ext.dirs. The verbose ANT log bears this out as well, no property/environment/classpath issues between them.
I can't tell from your EXEC example, but are you using full paths? Perhaps the PATH variable is an issue?
While not shown, I'm specifying the full paths to ANT and JAVA since I need to specify the ANT/JDK exactly to ensure I'm running the specific versions desired.
How are you invoking the generated build file with the wsgen tasks (wsgen-build.xml) that is having the problem?
The "main" build file invokes an EXEC on the "codegen" build file, as per the example above. The only difference is a different build target, one target is used for APT, another is used for the WSGEN piece. In said WSGEN target within the "codegen" build file, the wsgen-build.xml is currently imported and the target invoked via ANTCALL. I've also tried using just the ANT task, both have the same result.
Can you run your EXEC commands from the command shell?
Yes, if I run the step on the command line, it either works or not depending on if Java 7 or 8 is set as JAVA_HOME and which appears first on the PATH. For example, if I update JAVA_HOME to be Java 8, I get the following error: java.lang.NoClassDefFoundError: com/sun/mirror/apt/AnnotationProcessorFactory. This is correct since that class no longer exists in Java 8 (but does exist in 7).
Have you tried using a script or batch file instead of using EXEC on the ANT executable?
Yes, same error resulted. I tried this with a simple .bat file that set the requisite environment variables and invoked the command from the shell.
What OS are you on, have you tried a different machine/OS to see if this is environment specific?
I have a Win7 & a RHEL 7 environment, this problem happens in both and I'm using the osfamily attribute to conditional-ize the EXEC command per platform.
Ant 1.7.0 is pretty old, have you tried an updated Ant?
Same issue occurs using Ant 1.9.4 as well. The 1.9.4 Ant only runs for the "main" build file, the "codegen" build file will use 1.7.0 since I'm explicitly setting that via the EXEC tasks. I did try 1.9.4 even for the "codegen" ant build file, but it made no difference in the error.
If you managed to read thru this in its entirety, my hat off to you sir or madam! Thank you for any insight/advice you may have!
I'm using a #Grab annotation to grab the definition of an Html parser I can give to the XMLSlurper (I think it's the tagsoup parser) and all is good when I run my script from the cmd line. If I invoke the same script from Ant I get an Ivy NoClassDefFound error. I think it may berelated to having Ivy in Antlib. Is there another way to parse Html without customizing the slurper via #Grab?
This:
#Grab(group='org.ccil.cowan.tagsoup', module='tagsoup', version='1.2' )
doc = new XmlSlurper(new org.ccil.cowan.tagsoup.Parser()).parse(confluenceWebPageInputStream)
Works just fine from the command line but when I run it from an Ant build target:
<target name="update-wiki-chart">
<echo message="Will update chart for version ${version}"/>
<java dir="${basedir}" classname="groovy.lang.GroovyShell">
<arg value="ParseWikiPage.groovy"/>
<classpath refid="groovylib"/>
</java>
</target>
where groovyLib is a path ref pointing to the Groovy-1.8.6 jar downloaded from our internal Nexus repo, I get the NoClassDefFound error. I'm thinking this is probably due to having Ivy installed in Antlib causing the class loader to find it in two places. I just thought of something while writing this post. I can probably run java in forked mode or do something to cause it to not see/share Ant's classpath.It's been a few years since I've wrestled w/ Ant and class loader issues. My project is a little delinquent due to the bug and I'm looking for a quick/easy fix.
I just tried running my groovy on the cmd line via the "java" cmd and loading groovy-all jar in the class path and I realized that I get the NoClassDefFound error there as well. It has nothing to do with collisions with Ivy under Antlib. Rather, I am missing Ivy altogether. I had assumed it was included in Groovy-all.jar. I just need a clever way of passing Ivy from AntLib into my java task to get this all up and running.
Sounds like you're missing one or more jars from the classpath. I'd suggest digging around the classpathref you've labelled "groovylib".
A less error prone way to launch groovy from within ANT using the groovy ANT task.
Here's a similar example to your use-case:
Parse HTML using with an Ant Script
My example uses ivy directly to manage all build dependencies. The Grab annotations are still supported but obviously these would only manage the dependencies of the groovy script.
I am getting some problem while running ant
Here is the details of problem:
C:\jboss-5.1.0.GA\server\default\deploy\mdd_install\mc_config\ant\compile\compile.xml:30: Unable to find a javac compiler;
com.sun.tools.javac.Main is not on the classpath.
Perhaps JAVA_HOME does not point to the JDK
at org.apache.tools.ant.taskdefs.compilers.CompilerAdapterFactory.getCompiler(CompilerAdapterFactory.java:105)
at org.apache.tools.ant.taskdefs.Javac.compile(Javac.java:924)
at org.apache.tools.ant.taskdefs.Javac.execute(Javac.java:757)
at org.apache.tools.ant.Task.perform(Task.java:364)
at org.apache.tools.ant.Target.execute(Target.java:341)
at org.apache.tools.ant.Target.performTasks(Target.java:369)
at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1216)
at org.apache.tools.ant.Project.executeTarget(Project.java:1185)
I echo java_home and its value is correct
I am running my aplication from jboss and try to execute it, but it is getting the above exception. I put tools.jar in jboss server lib folder ,with that it is runnig fine,but it is not correct way.
Make sure the case of the path to JAVA_HOME is right. Reopen the window or environment you're running ant from to make sure it's using the updated environment vars.
I have an issue where my automated build environment necessitates a different version of ant than the actual delegated scripts being run to produce the build.
I do not have an environmental variable for ANT_HOME.
I throw my CI environment the ANT_HOME to a directory of ant-1.7.0
But i need to override or unset ANT_HOME to a directory of ant-1.6.5 so the targets I call don't inherit the ANT_HOME, and run out of the 1.7.0 folder.
Can anyone think of a good way to do this? I can't modify the delegated targets of the build script but I can modify anything in the front end.
I'm using Cruisecontrol2.8.4 and the aforementioned ant versions.
Edit: The build targets I call set their own ANT_HOME to the 1.6.5 folder but it is being ignored as the previously set ANT_HOME to invoke cruisecontrol is immutable
You can unset properties with AntContrib.
In your ant script...
Import AntContrib:
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<pathelement location="folderwithantcontribjar/ant-contrib-1.0b3.jar"/>
</classpath>
</taskdef>
Do the unset:
<var name="ANT_HOME" unset="true"/>
This removes ANT_HOME from the current set of properties allowing it to be set again.
Try setting the anthome attribute of the ant builder in your cruisecontrol configuration file :
http://cruisecontrol.sourceforge.net/main/configxml.html#ant
This should call your version of ant and presumably all called ant scripts will also use this version.
I have a large ant build that I'm working on, that is currently running out of memory. One ways I've read that can help mitigate this problem is to use javac fork="true"
to run javac in a separate jvm.
My problem is that I need to compile the project with the IBM JDK (this is not the JDK referenced by JAVA_HOME, and I would prefer it not to be). I tried setting the executable attribute of Ant's javac, to the path to IBM's javac but no joy (the project still won't compile). Ant's docs for the executable attribute state:
Complete path to the javac executable to use in case of fork="yes". Defaults to the compiler of the Java version that is currently running Ant. Ignored if fork="no".
Since Ant 1.6 this attribute can also be used to specify the path to the executable when using jikes, jvc, gcj or sj.
Does anyone have any ideas?
Thanks -
I have used a single ANT build to compile a set of classes in 1.7 and another set of classes in 1.6 and it works fine.
Both 1.7 and 1.6 are IBM JDK's. JAVA_HOME points to the 1.7 JDK & ANT version is 1.9
Below are the ANT tags used
1.7 compilation using JAVA_HOME
`<javac srcdir="${LOCAL_SOURCE_PATH}/temp" debug="true" deprecation="false" fork="true" memoryInitialSize="1024M" memoryMaximumSize="1500M" verbose="${verbose}">`
1.6 compilation using javac tags executable attribute
`<javac srcdir="${LOCAL_SOURCE_PATH}/branchtmp" fork="true" executable="${JAVA6_HOME}/bin/javac" compiler="javac1.6" debug="true" deprecation="false"memoryInitialSize="1024M" verbose="${verbose}">`
Hope this helps.