Getting CLASSPATH from environment in ant build.xml - java

How can I get the CLASSPATH from the environment in a build.xml?
I've tried
<property environment="env"/>
<path id="classpath">
<pathelement location="${env.CLASSPATH}"/>
</path>
<target name="compile">
<javac includeantruntime="false">
<src path="${src}"/>
<classpath refid="classpath"/>
</javac>
</target>
I have a feeling this is failing because ${env.CLASSPATH} is a colon-separated list.
How then, can I get my classpath? I was surprised when ant didn't use my environment's CLASSPATH.
EDIT:
I've found a quick solution, but the preferred method is to use a separate properties file like the example here http://www.java2s.com/Code/Java/Ant/Useseparatepropertyfile.htm
Solution is, add
<property name="build.sysclasspath" value="first"/>
to the top of the build.xml

Yes, it's failing because it's a colon-separated list. In general, it's considered a bad idea to specify the class-path externally and use it within Ant. This is because running the same Ant script on different machines may yield different results. Instead, you're better of specifying the class-path from within Ant.

Related

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

Could not find or load main class Java

Good evening Stack Overflow!
I started learning Java quite a few days ago, but not using an IDE once my computer is a bit slow. So, I decided to use Sublime Text, and compile things using ant on the cmd, since it seems to be the most reasonable thing to do.
Today I started ( at least tried ) to follow along a series of LWJGL tutorials (which are really cool), from ThinMatrix, but I can't manage to solve an error which I get every time I try to compile the 'project'.
This is the structure of my project:
LWJGL
src
com
game
test
MainGameLoop.java
renderEngine
DisplayManager.java
build.xml
And ladies and gentlemen... the build.xml (following Ant's official HelloWorld tutorial):
<project name="LWJGL" basedir="." default="main">
<property name="src.dir" value="src"/>
<property name="build.dir" value="build"/>
<property name="classes.dir" value="${build.dir}/classes"/>
<property name="lib.dir" value="lib"/>
<property name="jar.dir" value="${build.dir}/jar"/>
<property name="main-class" value="com.game.test.MainGameLoop"/>
<path id="classpath">
<fileset dir="${lib.dir}" includes="**/*.jar" />
</path>
<target name="clean">
<delete dir="${build.dir}"/>
</target>
<target name="compile">
<mkdir dir="${classes.dir}"/>
<javac srcdir="${src.dir}" destdir="${classes.dir}" includeantruntime="false" classpathref="classpath" />
</target>
<target name="jar" depends="compile">
<mkdir dir="${jar.dir}"/>
<jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}">
<manifest>
<attribute name="Main-Class" value="${main-class}"/>
</manifest>
</jar>
</target>
<target name="run" depends="jar">
<java jar="${jar.dir}/${ant.project.name}.jar" fork="true">
<jvmarg value="-Djava.library.path=lib/natives-win" />
</java>
</target>
<target name="clean-build" depends="clean,jar"/>
<target name="main" depends="clean,run"/>
Every time I run ant on the command line, inside the root folder of my project, I get this:
[java] Error: Could not find or load main class com.game.test.MainGameLoop
[java] Java Result: 1
I'm struggling to understand what is the root problem of this, I kinda sexually abused Google Search trying to find an answer on Java forums, Blogs, and even here...
I don't usually like populating Stack Overflow with noob questions, but I have to admit I don't know what to do.
Thanks in advance!
Your code depends on libraries. You have successfully added the libraries in the classpath to compile your code, and have thus successfully created an executable jar files containing your classes. But these classes depend on libraries to run. And when running the jar file, you don't secify anywhere that Java should look for classes in libraries in addition to your jar file.
See Generate manifest class-path from <classpath> in Ant for how to add a Class-Path entry to the manifest of your executbale jar file. Beware: the paths of the libraries must be relatie to the path of the jar.
Ant is a bit outdated. If I were you, I'd try using gradle, which has a neat application plugin doing all that for you, and much more.
I finally managed to solve this problem that I was struggling with by the help from a good friend of mine. There are two tricky points:
First, when specifying the "Main-Class" in the manifest section, just use the following format "packageName.className", and there is no need to specify the "build" or "source" folders!
Second, try and zip all the jar files that your "jar" file is going to depend on using "zipgroupfileset"
This image shows how I have commented out the "Class-Path" attribute that I would use for addressing the dependencies of the project, and have replaced it with the "zipgroupfileset". I hope that help you as well.
Small thing that can cause this issue is using uppercase letters in file extension. For example you can't use MainGameLoop.Java, The correct extension should be all lowercase like below.
MainGameLoop.java
Please check that first.

How to add external .jar to android project? (with certain conditions)

I need to add some external .jar files to my android project BUT
1) without using Eclipse or any other IDE (so no .classpath)
2) without copying them to /libs folder, i need them to stay where they are
How can i accomplish that? I know that ant should have this functionality but and cant find it. It would be great if there is something like adding "android.library.reference" to project.properties but for .jar instead of library project.
i am not sure that it will work for you but you can use this
<path id="class.path">
<fileset dir="jar_folder">
<include name="**/*.jar" />
</fileset>
</path>
and you can use it in javac command as
<javac executable="${env.JAVA_HOME}/bin/javac" encoding="utf-8" srcdir="src/" destdir="temp/" debug="on" debuglevel="lines,source,var" fork="true" memoryInitialSize="256m" memoryMaximumSize="1024m">
<classpath refid="class.path" />
</javac>

Classpath, Compile, and Run with Ant?

I'm completely new to Ant and need to add a couple jars to my classpath, compile a couple .java files, and run a junit test, all in Ant. I've been looking at a few online tutorials and manuals, but can't seem to wrap my head around the entire xml writing process.
All the previously-written code resides in a single directory called XXX.
In XXX there are two jars I need to add to my classpath with export CLASSPATH=$CLASSPATH:jar1:jar2, two java files I compile with javac *.java, one of which contains several junit tests that I run with java org.junit.runner.JUnitCore Tests. The build.xml would reside in XXX as well (I believe).
So far I have the following for just compiling, although I think there's a lot missing.
<?xml version="1.0"?>
<project name="EtlAutomation" default="compile" basedir=".">
<property name="src" value="${basedir}"/>
<target name="compile">
<!-- Compile .java files -->
<javac srcdir="${src}" destdir="${src}"/>
</target>
</project>
What else do I need to add to compile *.java in the current directory? How can I run the export CLASSPATH command, and finally the junit commend?
I'm not asking for anyone to write my code, but it would be appreciated. If anyone knows a good beginner tutorial for a unix environment, that would be awesome. I'm a total beginner with ant so I'll take what I can get.
Here is a previous question addressing this. And this may work for you:
<project name="EtlAutomation" default="compile" basedir=".">
<property name="src" value="${basedir}"/>
<path id="compile.classpath">
<fileset dir="./">
<include name="*.jar"/>
</fileset>
</path>
<target name="compile" >
<javac destdir="${src}" srcdir="${src}">
<classpath refid="compile.classpath"/>
</javac>
</target>
<target name="run" depends="compile">
<junit>
<classpath refid="compile.classpath" />
<test name="TestExample" />
</junit>
</target>
</project>

How can I exclude sources in a javac task in ant?

I have the following in my build.xml:
<target name="compile.baz" depends="init">
<javac destdir="${build.dir}/classes" debug="on">
<compilerarg value="-Xlint:deprecation"/>
<src>
<pathelement location="${src.dir}/com/foo/bar/baz/" />
<pathelement location="${src.dir}/com/foo/bar/quux/" />
<!-- Need to exclude ${src.dir}/com/foo/bar/quux/dontwant/ -->
</src>
<classpath refid="classpath.jars" />
</javac>
...
</target>
This mostly does what I want, except that (as the comment says) I do not want the files in
${src.dir}/com/foo/bar/quux/dontwant/ to be compiled by this task (but I do want everything else under ${src.dir}/com/foo/bar/quux/ to be compiled in this task).
I'm a complete ant n00b, and the documentation hasn't been much help to me. I see several places where it says there are various exclude/excludes elements/attributes, but every variation I can think of either has no effect or results in an error like "blah doesn't support the 'exclude' attribute".
A couple of people suggested using <exclude>. This didn't work with the way my task was specified. trashgod's answer linked to the sixth example on this page which gave me an idea of how to restructure my task specification.
It looks like my problem was related to the way I was specifying the source files. Rather than using <pathelement> elements in a <src>, like this:
<src>
<pathelement location="${src.dir}/com/foo/bar/baz/" />
<pathelement location="${src.dir}/com/foo/bar/quux/" />
</src>
I switched to using a single <src> with a path and then a set of <include> elements, like this:
<src path="${src.dir}" />
<include name="com/foo/bar/baz/**" />
<include name="com/foo/bar/quux/**" />
This appears to be functionally identical, but is compatible with the use of <exclude>:
<exclude name="${src.dir}/com/foo/bar/quux/dontwant/**"/>
(Actually, I'm surprised that what was there in the first place worked at all.)
From my experiments you should not include full path for file you want to exclude.
This one doesn't work:
<javac>
(...>
<exclude name="${src.dir}/com/foo/blah/blah1/FILENAME.java"/>
(...)
</javac>
but this one does:
<javac>
(...>
<exclude name="com/foo/blah/blah1/FILENAME.java"/>
(...)
</javac>
Try
<javac>
(...>
<exclude name="${src.dir}/com/foo/bar/quux/dontwant/*" />
(...)
</javac>
I'm not sure about the rest, but the <exclude/> nested element should work in the Javac task. See the sixth example down.
Addendum: Patterns, including the ** notation, are discussed in Directory-based Tasks.
<target name="compile.baz" depends="init">
<javac destdir="${build.dir}/classes" debug="on">
<compilerarg value="-Xlint:deprecation"/>
<src>
<pathelement location="${src.dir}/com/foo/bar/baz/" />
<pathelement location="${src.dir}/com/foo/bar/quux/" />
</src>
<exclude name="${src.dir}/com/foo/bar/quux/dontwant/**"/>
...
</javac>
...
</target>
If you are trying to exclude Java classes but Ant is still trying to compile them then this may be due to references to these classes in your code.
If A.java has a reference to B.java and you try to exclude B.java then compiling A.java will require that B.java is compiled too.
This is one reason for interfaces in Java, so you can compile the interface without needing to compile the implementations.
try
folder "test" under {source.dir} would not be complied
<javac destdir="${compile.dir}" ...>
<src path="${source.dir}" />
<exclude name="test/**"/>
</javac>

Categories

Resources