Why is my Ant classpath ok in Eclipse but empty on Jenkins? - java

I am running my Ant build.xml file both locally and on a server running Jenkins.
Locally, inside Eclipse, the build works wonderfully. I set the classpath using:
<path id="classpath">
<fileset dir="${lib.dir}" includes="**/*.jar" />
</path>
and then I use the following when I run a target:
<javac srcdir="${src.dir}" destdir="${build.dir}" includeantruntime="false">
<classpath refid="classpath" />
</javac>
When I debug using echo the classpath shows all the available jars which are in my project/lib folder.
However, when I Jenkins fetches this build.xml file and runs it remotely, it prints an empty classpath (using the same echo target).
Why do my class paths differ based on Eclipse versus Jenkins?

Your build environment on you Jenkins server is going to look a bit different from your desktop dev env.
Sanity check: where/how is ${lib.dir} provided with a value?
Usually it is set with a property in the build file - can you maybe post that here also?

Related

Javac inexplicably failing on Hudson

Our application is built my Hudson from Ant scripts. In my latest work I've recently included Maven. Now Hudson's build process fails when it reaches the compilation task without any explanation.
Hudson build:
[echo] Using Maven Repo at ../.maven/repo/
[javac] Compiling 134 source files to C:\Users\administrator1\.hudson\jobs\SAP_RC\workspace\current\classes
BUILD FAILED
C:\Users\administrator1\.hudson\jobs\SAP_RC\workspace\current\build.xml:68: Error running C:\Program Files (x86)\Java\jdk1.8.0_66\bin\javac.exe compiler
Ant script:
<javac classpathref="lib" destdir="${classesDir}" debug="true" debuglevel="lines,vars,source" verbose="true" fork="true" nowarn="true" memoryMaximumSize="320m" srcdir="${srcDir}" includeantruntime="false" />
I specifically included the Maven repo into the classpath, and that's when it fails inexplicably. When I remove the Maven repo the build throws a compilation error complaining that it can't find Maven dependencies. This makes me suspect that I'm hitting some classpath length limit.
I did it this way because I'm not sure what is the correct way to include Maven dependencies into the classpath. If there is a better way please tell me and I'll open a new question specifically for that.
It seems as though my wildcard in my fileset was the culprit.
<path id="lib">
<fileset dir="${env.maven_repo}">
<include name="*/**"/>
</fileset>
</path>
I changed the ** to *.jar and the build process is no longer (inexplicably) failing.
<path id="lib">
<fileset dir="${env.maven_repo}">
<include name="*/*.jar"/>
</fileset>
</path>

Building with Ant in Eclipse - javac not recognizing lambda expression (Java 1.8)

I am trying to build an existing project using Ant in Eclipse. The problem is that javac does not recognize the use of a Lambda expression (error: illegal start of expression) in one of the files, and the build fails during the compile phase of the Ant.
Within Eclipse, I've ensured that the Java Compiler compliance level is set to 1.8 and that Java 8 is in the Java Build Path.
I've also ensured that the my Path, JAVA_HOME, and JRE_HOME all point to my Java 8 directory (in Path it points to the /bin directory).
For giggles, the compile section of my build.xml file is:
<target name="compile" depends="setup">
<javac destdir="${base}/${build.dir}"
srcdir="${base}/${src.dir}"
deprecation="true"
verbose="false"
includeantruntime="false">
<classpath refid="libs" />
</javac>
</target>
I'm not really sure what to do next. I've resorted to restarting Eclipse hoping for magic to happen. Any suggestions or help are welcome! Thanks in advance.
Adding <echo> Java version: ${ant.java.version}</echo> to my build.xml revealed that Ant was still running Java 1.7.
I added the directory location of my Java 8 javac and modified the javac task with the executable and fork attributes to use it:
<property name="javac1.8" location="/path/to/java8/bin/javac" />
<target name="compile" depends="setup">
<javac executable="{$javac1.8}" fork="yes"
destdir="${base}/${build.dir}"
srcdir="${base}/${src.dir}"
deprecation="true"
verbose="false"
includeantruntime="false">
<classpath refid="libs" />
</javac>
</target>
Thanks so much for the comments #Jim Garrison, #wero, and #greg-449. Your powers combined lead me to my answer.

Why combine all jars together?

I have create RESTful web service based on the JAX-RS and used Jersey embedded web server. My ant script compiles code successfully while it gives me error ClassNotFoundException when I run my main class. So after doing research I came up with solution & here it goes java build ant file with external jar files . What I did was created a bundled jar file try to execute that & it works perfectly fine. I want to know the reason behind :
why this solution works ?
Why I should combine all jar file ?
Is it similar to war file which we create following J2EE architecture otherwise war will not be extracted by server ( say TOMCAT ) & in my case jar file for Jersey embedded HTTP server?
EDIT:
Here is my ant build.xml file
<property name="lib.dir" value="${user.dir}/lib"/>
<property name="build.dir" value="${user.dir}/build"/>
<property name="build.lib.dir" value="${build.dir}/lib"/>
<property name="build.classes.dir" value="${build.dir}/classes"/>
<property name="src.dir" value="${user.dir}/src/main/java"/>
<property name="main.class" value="com.assignment.ConsoleServer"/>
<path id="classpath">
<fileset dir="${lib.dir}" includes="**/*.jar"/>
</path>
<target name="clean">
<delete dir="${build.dir}"/>
</target>
<target name="init" depends="clean">
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build.dir}"/>
<mkdir dir="${build.classes.dir}"/>
</target>
<target name="copy_jars" depends="init" >
<copy todir="${build.lib.dir}" >
<fileset dir="${lib.dir}">
<include name="**/*.jar" />
</fileset>
</copy>
</target>
<target name="compile" depends="copy_jars">
<javac srcdir="${src.dir}" destdir="${build.classes.dir}" classpathref="classpath" includeantruntime="false"/>
</target>
<target name="jar" depends="compile">
<jar destfile="${build.dir}/${ant.project.name}.jar" basedir="${build.classes.dir}">
<manifest>
<attribute name="Main-Class" value="${main.class}"/>
</manifest>
<zipgroupfileset dir="${lib.dir}" includes="*.jar"/>
</jar>
</target>
<target name="run" depends="jar">
<java fork="true" classname="${main.class}">
<classpath>
<path refid="classpath"/>
<path location="${build.dir}/${ant.project.name}.jar"/>
</classpath>
</java>
</target>
Here is my folder structure
P.S. I am not java expert so pardon me if this question is stupid.
Why this solution works?
In your particular case, you probably didn't include all of the necessary dependencies in your deployment in your previous. (It is not clear from your question how you were originally doing the deployment.)
Now you have put all of the application and dependent class files, etc into one JAR file, and presumably you are deploying / running that file. It works because now it has everything that it needs to run ... which it didn't before.
Why I should combine all jar file?
In your case I suspect that it was not strictly necessary. There was probably a way to "deploy" all of the dependencies without combining them into a single JAR file.
However, there is one case where a "uber-jar" has advantages. That is when the JAR is intended to be an "executable" JAR, and you want to be able to distribute / install it as a single file. (And executable JAR
file can refer to external JARs, etc, but the way that you have to do
it is "fragile".)
Is it similar to war file ... ?
Sort of, though a WAR file contains JAR files ... and typically other kinds of resources that the web-container understands.
The solution works because you packed all you service classes and depending libraries in one jar. That jar and everything inside will be in the class path and visible to your execution virtual machines class loader.
If you leave your depending libraries out your Jersey Web server needs to have them on it's class path, then you wouldn't get ClassNotFoundExcpetion
You shouldn't pack web application in single jar. You should crate war file where you dependencies will be placed inside WEB-INF/lib. You would easily then deploy that war on any application server. Switching to Maven instead of Ant can help a lot.
EDIT: After you added more details to description and ant
If you don't want to use fat-jar you can either
modify your antjava task to specify classpath that will reference
all external libraries (basically telling ant how to build
-classpath parameter for java -jar command
even better, modify your javac ant task by making complete Manifest file that specifies Class-Path correctly, take a better
look at the solution (at the bottom) of the answer you linked (java build ant file with external jar files)
For completness reference on Manifest here

System property, "java.class.path" does not contain classpath added from ant script

I added classpath to an ant script. Then, in a java file, I wrote "java.class.path" property to get the classpath. When I run a test suite in Eclipse, the classpath is in the property value. However, when I ran the test suite with ant script in terminal, the classpath is not in the property value. I couldn't find the reason.
Here is the ant script snippet. I added "target/class" and jar files to the classpath.
<target name="test">
<echo message="Running unit tests ..."/>
<junit printsummary="true"
showoutput="true"
haltonfailure="false">
<formatter type="plain" usefile="false"/>
<classpath>
<pathelement path="${result.classes.dir}"/>
<path refid="jmeter_cp"/>
</classpath>
<test name="test.JMeterTestSuite"/>
</junit>
</target>
And here is java code snippet. It retrieves "java.class.path" property value.
stPaths = new StringTokenizer(
System.getProperty("java.class.path"),
System.getProperty("path.separator"));
I looked at the "java.class.path" value, but it did not have "target/class" and the jar files...
FYI, I'm using an modified ant from a mutation tool(http://mutation-testing.org/). "java.class.path" value contains only libraries for the tool. The tool might delete the classpath that I added. But I'm not sure, so this is why I'm posting this question here.

ant deploy problem

I am working on a spring project. I use ant to deploy application and STS (eclipse based) IDE to develop. I set the CATALINA_HOME environment variable
echo $CATALINA_HOME
/home/username/springsource/apache-tomcat
When I run the deploy ant task from IDE it deploys to a folder under
/home/username/workspace/myproject/${env.CATALINA_HOME}/webapp
but not
/home/username/springsource/apache-tomcat/webapp
Do you know any fix?
My build.properties file
src.dir=src
web.dir=web
build.dir=${web.dir}/WEB-INF/classes
name=myproject
appserver.home=${env.CATALINA_HOME}
deploy.path=${appserver.home}/webapps
appserver.lib=${appserver.home}/lib
and build.xml file
<?xml version="1.0" encoding="UTF-8"?>
<project name="kervan" basedir="." default="usage">
<property environment="env"/>
<property file="build.properties"/>
<path id="cp">
<fileset dir="${web.dir}/WEB-INF/lib">
<include name="*.jar"/>
</fileset>
<fileset dir="${appserver.lib}">
<include name="servlet-api.jar"/>
</fileset>
<pathelement path="${build.dir}"/>
</path>
<target name="usage">
<echo message=""/>
<echo message="${name} build file"/>
<echo message="-----------------------------------"/>
<echo message=""/>
<echo message="Available targets are:"/>
<echo message=""/>
<echo message="build --> Build the application"/>
<echo message="deploy --> Deploy application as a WAR file"/>
<echo message=""/>
</target>
<target name="build" description="Compile main source tree java files">
<mkdir dir="${build.dir}"/>
<javac destdir="${build.dir}" source="1.6" target="1.6"
debug="true" deprecation="false" optimize="false"
failonerror="true">
<src path="${src.dir}"/>
<classpath refid="cp"/>
</javac>
</target>
<target name="deploy" depends="build" description="Deploy application as a WAR file">
<war destfile="${name}.war"
webxml="${web.dir}/WEB-INF/web.xml">
<fileset dir="${web.dir}">
<include name="**/*.*"/>
</fileset>
</war>
<copy todir="${deploy.path}" overwrite="true">
<fileset dir=".">
<include name="*.war"/>
</fileset>
</copy>
</target>
</project>
Try putting the following after the two <property> lines:
<echo message="CATALINA_HOME=${env.CATALINA_HOME}" />
and see what it outputs. If it in fact outputs the correct value, then something strange may be happening. If it outputs the literal string
CATALINA_HOME=${env.CATALINA_HOME}
then somehow your ant script hasn't picked up the environment variable.
Note that when you set an environment variable for your system, only applications launched AFTER the variable is set will recognize the new variable. And variables set from the command line will only be recognized if the application being launched is being launched from that same command line session.
If you're running from within Eclipse or an Eclipse-like environment, Eclipse can be kind of weird in that depending on how you launch it, it's startup scripts won't make your environment natively available to your in-IDE Ant build process.
With my Eclipse-based Ant build, I had to manually set the environment. So for me, I right click on my project & go to "Properties". Then I click on the "Builders" section. I select my "Ant Builder" and click "Edit...". Under this section there's an "Environment" tab where you can specify environment variables and their corresponding values.
Even if you're not using Eclipse exactly like I was, poke around in the build properties and you should be able to find a way to specify environment variables and make them available to the build process.
Is CATALINA_HOME set in your environment?
e.g. Windows
echo %CATALINA_HOME%
Linux
echo $CATALINA_HOME
You could always hardcode the value in your properties file if it's not getting resolved correctly but provided it's in your environment then it should work.
The forum here discusses the same problem:
http://www.nabble.com/%3Cproperty-environment%3D%E2%80%9Denv%E2%80%9D%3E-doesn%27t-pick-up-an-environment-variable-td21481164.html
When run from eclipse, I don't believe the environment is passed to ant. You will have to specify each of the environment variables (and the values) that you want passed to ant in the configuration of the build file within eclipse.
if you are set your environmental variable in global
/etc/environment
thats the problem in Ubuntu. Ant does not pick the environment variable from here.
But the echo $CATALINA_HOME works fine in terminal. I am facing the same problem.
set your environment in .bashrc may fix your problem.
I recently suffered a similar issue.
The problem was in the CATALINA_HOME environment variable: I needed to close the path with a backslash ("/"):
$ export CATALINA_HOME=/home/username/springsource/apache-tomcat/
After fixing that I could deploy the application with ant.
Please make sure you end your path with a / and it shall solve your problem.
example: export JAVA_HOME=/opt/java/
instead of: export JAVA_HOME=/opt/java

Categories

Resources