windows classpath issue with ant and java - java

I've been fighting in these trenches for a while now and have yet to get this working. Using many examples here on SO as well as others like this blog or this SO post, I still cannot get past the windows classpath limit. I'm currently just dealing with an ant task that runs a single main method in a java class within my source. If I can get this working here, I can extrapolate elsewhere.
First, my original relevant build tasks
<path id="code.classpath">
<path id="code.classpath">
<path refid="jars.code"/>
<path refid="jars.common"/>
<path refid="jars.servlet-api"/>
<dirset dir="${code.dir}" excludes="xlib/scripts/**"/>
</path>
<target name="code.exec" description="Execute a class file">
<echo>${code}</echo>
<input addproperty="code.exec.class">Enter full class name (e.g. ${atmr.pkg}.FooBar):</input>
<input addproperty="code.exec.args">Enter arguments:</input>
<java classname="${code.exec.class}"
fork="true"
dir="${code.src.dir}"
failonerror="true"
classpathref="code.classpath">
<jvmarg value="-Xmx4048M"/>
<jvmarg value="-ea"/>
<jvmarg value="-Dlog4j.configuration=file:${basedir}/log4j.xml"/>
<syspropertyset refid="proxy.properties"/>
<assertions refid="code.exec.assertions"/>
<arg line="${code.exec.args}"/>
</java>
</target>
Next, my most recent attempt at a solution
<path id="code.source">
<dirset dir="${code.dir}" excludes="xlib/scripts/**"/>
</path>
<target name="code.classpath.acme">
<manifestclasspath property="jar.classpath" jarfile="${app.dir}/acme.jar">
<classpath refid="code.source"/>
</manifestclasspath>
<jar destfile="${app.dir}/acme.jar" index="true">
<manifest>
<attribute name="Class-Path" value="${jar.classpath}"/>
</manifest>
</jar>
</target>
<path id="temp.classpath">
<pathelement path="${app.dir}/acme.jar"/>
</path>
<target name="code.exec" description="Execute a class file" >
<property name="myclasspath" refid="temp.classpath"/>
<echo>${code}</echo>
<echo>${basedir}</echo>
<echo>${myclasspath}</echo>
<input addproperty="code.exec.class">Enter full class name (e.g. ${atmr.pkg}.FooBar):</input>
<input addproperty="code.exec.args">Enter arguments:</input>
<java classname="${code.exec.class}"
fork="true"
dir="${code.src.dir}"
failonerror="true"
classpathref="temp.classpath">
<jvmarg value="-Xmx4048M"/>
<jvmarg value="-ea"/>
<jvmarg value="-Dlog4j.configuration=file:${basedir}/log4j.xml"/>
<syspropertyset refid="proxy.properties"/>
<assertions refid="code.exec.assertions"/>
<arg line="${code.exec.args}"/>
</java>
</target>
Basically, when running the first one, I get the "classpath is too long" issue in windows. Running the second one, I get "could not find or load main class package.classname." I've gone through the MANIFEST.MF that is created in the jar and the package location is present. From here went my travels down the rabbit hole to find what could be up. I've tested different permutations of the manifest relative locations to no avail. I've even gone in and manually changed the manifest to an explicit file location (not relative to the jar) with no change in results.
To confirm that the overall code works, I can add my code.dir path into temp.classpath and get the too long error. I can also make the acme jar build with the classes within it and get past the issue with the missing class.
Everywhere I read, this should work. Yet, here I am. I know that if the reference in the manifest can't be found, it silently skips it. That is what it seems to be doing, yet I've tried everything to get it to see what's there to no avail. And thus, I turn to you SO contributors to either point out the silly mistake I've missed, or let me in on the secret knowledge that I have yet to learn.
Thanks in advance.

You were perhaps closer with your original answer if you can at least achieve 'classpath is too long' answer.
Have you tried nesting your paths in order to make them 'relevant' rather than 'absolute' and thus shorter? perhaps using an alias such as the way you might list 'JAVA_HOME' in your PATH variable?
A way to test this quickly from the command line would be to edit the classpath and be sure to clear it out when you try to re-set it in code. In windows that would look like the following:
C:\WINDOWS>setx CLASSPATH "CLASSPATH;C:\some_new_path"
This will update the PATH by appending the new path to the existing path value. Typing the following command will print the new PATH in all future CMD windows; NOT in the current CMD window:
C:\WINDOWS>CLASSPATH
Typing the following will give you a list of all the environment variables:
C:\WINDOWS>set

Related

Java Orchestration

I got 5 different .JAR's that I want to "run" with Apache Ant. I would like to give each of them some kind of "Order"-ID, (1 to 5) and have one JAR that runs all the other fives if they are selected.
Example: Component1, Component2, Component3, Component4, Component5 should be in the folder "job". I got a file called order.properties which looks like this: ComponentA = true, ComponentB = false and so on. Main.Jar should read order.properties and run all the Components that are "true" in the order that they are listed in the properties file.
I don't have any clue if thats possible and how because I simply don't know where to start looking for.
Yes, you can run tasks.
<java classname="test.Main">
<arg value="-h"/>
<classpath>
<pathelement location="dist/test.jar"/>
<pathelement path="${java.class.path}"/>
</classpath>
</java>
https://ant.apache.org/manual/Tasks/java.html

Ant can't find Maven's "DependenciesTask"

I'm at a loss at what's wrong. I have an Ant build.xml that has the line
<path id="maven-ant-tasks.classpath" path="lib/maven-ant-tasks-2.1.3.jar" />
and then later
<target name="clean">
<artifact:mvn pom="${basedir}/pom.xml">
<arg value="clean"/>
</artifact:mvn>
The error I get is
java.lang.NoSuchMethodError: org.apache.maven.artifact.ant.DependenciesTask.setPathType(Ljava/lang/String;)V
The .jar file exists in the Ant's lib/ folder, and it also contains said function (unzipped it and looked at .class file). Also, when I change the path in the "path=" attribute, it doesn't complain, which means it's not even looking!
Anyone have an idea why it's not even considering the "path=" element here? Strangely enough, for other people in my group it works, and it has for me too in the past (had to rebuild my machine and reinstall everything).

Apache Ant {Compile javac srcdir} does not exist

I am new to apache ant and I am currently working on an apache Ant project. I Just started out, imported the project into workspace and tried to run the build.xml. I added all the libraries that come with the original project to the build path. I am having the following problem. Please someone else wrote the code and I am supposed to improve it. The directories this is all about exist in the project directory.
BUILD FAILED
C:\workspace\MyApp\build.xml:83: srcdir "C:\workspace\MyApp\${compile.javac.srcdir}" does not exist!
The error code is referencing the following part of the build.xml file
<target name="compile.default" depends="init">
<javac fork="yes" srcdir="${compile.javac.srcdir}" destdir="${compile.javac.destdir}" includes="${compile.javac.include}" excludes="${compile.javac.exclude}" classpath="${compile.javac.classpath}" debug="${compile.javac.debug}" optimize="${compile.javac.optimize}" deprecation="${compile.javac.deprecation}" verbose="${compile.javac.verbose}">
</javac>
<copy todir="${compile.javac.destdir}">
<fileset dir="${compile.javac.srcdir}" includes="${compile.copy.include}" excludes="${compile.copy.exclude}"/>
</copy>
</target>
<target name="compile" depends="init,compile.default" description="Compile all java source">
</target>
<!--+++++++++++++++-->
<!-- lib target(s) -->
<!--+++++++++++++++-->
<target name="lib.default" depends="init,compile">
<xmlbean schema="config/schemas/validate/1.0/validate.xsd" destfile="lib/glx-beans.jar" classpath="lib/xbean.jar:lib/jsr173_1.0_api.jar" />
<jar jarfile="${lib.filename}">
<fileset dir="${lib.srcdir}" excludes="${lib.exclude}" />
</jar>
</target>
<target name="lib" depends="init,compile,lib.default" description="Create all Project Libraries">
</target>
Would you please tell me what I am missing?
The ${compile.javac.srcdir} isn't defined. There are a few possibilities:
This is defined not in the build.xml, but in some sort of properties file. See if you have something like <property file="..."/> in your build script. My recommendation is to have all properties defined in the build.xml file, and use a properties file to override those settings. This way, the only build file that a developer needs in the build.xml file and doesn't have to worry about setting up a separate build.porperties file.
This is defined in the build.xml file under a particular task, but you forgot to say that your target where you use thisis dependent upon this task.
One of the things you can do is use the -d parameter when running Ant. I run the following command when running Ant with the -d parameter:
$ and -d 2>&1 | tee ant.out
I can then look at ant.out and see if somehow I didn't define that particular property. Maybe I had the wrong capitalization or misspelled the property name. For example, it's very likely I'll define the property as copmile.javac.srcdir because I don't know how to spell. Looking at the -d output can quickly point these types of errors out.
By the way, you shouldn't have all of your tasks dependent upon init since they're dependent upon compile.default anyway:
<target name="compile.default" depends="init">
....
</target>
<target name="compile" depends="compile.default">
....
</target>
<target name="lib" depends="compile,lib.default">
....
</target>
If I run the target lib, it will see compile is dependent upon compile.default which is dependent upon init. Thus, your build will run init, then compile.default, then compile, then 'lib.defaultand finallylib`.
If the init task is just setting up properties, you can do that outside of any task. Then, these properties will be setup before any task is executed. This way, they're not forgotten. If your init is also creating directories, you may want to move those <mkdir/> tasks in front of the task where that directory is used. For example, you may want to make the destdir uses in javac before the <javac/> task.
I find assigning default properties outside of any task, and creating directories before they are needed to simplify the build.xml. Plus, you're not creating a whole flock of unused directories if the user is merely compiling and not packaging the jar/war/etc.

Can I declare and initialize a variable in an Ant script?

In Ant, can I create a target that contains something like a variable that represents a path?
For example, something like the following pseudo target:
<target name="initPath">
Path = "${basedir}/../../myProject/Project/"
</target>
Where Path is my variable and is initializated to specific value.
How can I do this?
Ant build scripts are written in XML. To create a property has to be in XML style, so instead of this:
some_prop="some value"
It is this:
<property name="some_prop" value="some value"/>
Properties can contain periods, and I recommend using them as name separators:
<property name="some.prop" value="some value"/>
How do you declare a constant? Here:
<property name="some.prop" value="some value"/>
That's because once a property is set, it cannot be changed.
This way, you can do something like this:
<property file="${basedir}/build.properties"/>
<property name="some.prop" value="some value"/>
Let's say that the build.properties file contains this line:
some.prop="Some other value"/>
Now, when you run your Ant build file, the value of some.prop will be "Some other value", and the <property name="some.prop" value="some value"/> won't change it. I could even do this:
$ ant -Dsome.prop="A completely different value"
And this value of the some.prop property will override what I have in my build.properties file and what I have in my Ant build file.
This is a very nice feature. It allows me to set a default value that developers can override:
<property name="copy.verbose" value="false"/>
...
<copy todir="${copy.to.dir}"
verbose="${copy.verbose}">
<fileset dir="${copy.from.dir}"/>
</copy>
By default, when my copy task runs, it runs in non-verbose mode which is what I want. However, let's say I am having a few problems with my build, and I want to see exactly what is being copied, I could do this:
$ ant -Dcopy.verbose=true
And, now my copy tasks will show me all the files being copied.
A path is a way to declare something like $CLASSPATH or $PATH in the command line. You can predeclare a path with an id, and then use it later:
<javac destdir="${main.destdir}"
srcdir="${main.srcdir}">
<classpath>
<fileset dir="${lib.dir}">
<include name="*.jar"/>
</fileset>
</classpath>
</javac>
Here I'm adding a classpath. This is using <fileset/> to create a classpath based upon all of the jars in my ${lib.dir} directory.
I can also do this:
<path id="main.classpath">
<fileset dir="${lib.dir}">
<include name="*.jar"/>
</fileset>
</path>
<javac destdir="${main.destdir}"
srcdir="${main.srcdir}"
classpathref="main.classpath"/>
Here, I predeclare my main.classpath and then use that later in my <javac> task.
You should read up on Ant in the on line Ant Manual. There is a semi-decent introduction in the manual which might help clarify a few issues for you.
Here is how you can define a property in Ant script.
Unfortunately it is not a variable, since they are immutable. You can set a value to it, but you cannot change it during your script execution.
Here you can see an example of assigning value to a property.
Update.
You can use path task. For example:
<path id="combinedPath">
<path path="${toString:oldPath}"/>
<path path="my.jar"/>
</path>
<path id="reanamePath">
<path path="${toString:oldPath}"/>
</path>
If you change path in one target you can definitely access it in another one.
Ant has classpath-like support built-in.
In general you wouldn't use a property for this functionality.
Please consider reading the Ant documentation; this is Ant 101 and it'll be quicker in the long run if you spend some time with the docs and figuring out the Ant way of doing things.

What is the difference between the <pathelement> attributes 'path' and 'location' in Ant?

I was running Selenium unit tests in TestNG with the Ant Java task like so:
<java classpathref="runtime.classpath"
classname="org.testng.TestNG"
failonerror="false">
<arg value="-d" />
<arg value="${grid.location}/target/reports" />
<arg value="${lib.location}/testng.xml"/>
</java>
runtime.classpath is a pathlike structure that included <pathelement path="${basedir}/target/classes/" />, which I thought was needed to let TestNG know which classes to run.
<path id="runtime.classpath">
...
<!-- Target classes -->
<pathelement path="${basedir}/target/classes/" />
</path>
However, I kept seeing in the log that TestNG found 0 applicable classes.
I eventually got some help from a colleague and it appears this was the key change:
<path id="runtime.classpath">
...
<!-- path attribute changed to location -->
<pathelement location="${basedir}/target/classes/" />
</path>
This also pulls in the test classes correctly:
<java classpathref="runtime.classpath"
classname="org.testng.TestNG"
failonerror="false">
<arg value="-d" />
<arg value="${grid.location}/target/reports" />
<arg value="${lib.location}/testng.xml"/>
<classpath>
<pathelement location="${basedir}/target/classes/" />
</classpath>
</java>
What is the difference between the path and location attributes? I've looked at Writing a Simple Buildfile (specifically the Path-like Structures section), but in that manual it looks to me like location is more specific than path. That doesn't appear to be the case empirically, but I can't quite figure out why.
It looks like the difference between path and location is many entries vs one. A location is a file or directory, a path can be a list.
From the manual
The location attribute specifies a single file or directory relative
to the project's base directory (or an absolute filename), while the
path attribute accepts colon- or semicolon-separated lists of
locations. The path attribute is intended to be used with predefined
paths - in any other case, multiple elements with location attributes
should be preferred.
Note that the JVM used by ant has just about no relation to the JVM used by the java task. By default the environment of ant isn't the same as that of things started with the java task via ant. This is actually helpful when you want to use a different JVM from the one ant wants to use and makes things explicit, helping avoid surprises later on.
Check out the docs for the java task, particularly clonevm
clonevm: If set to true, then all system properties and the
bootclasspath of the forked Java Virtual Machine will be the same as
those of the Java VM running Ant. Default is "false" (ignored if fork
is disabled). since Ant 1.7

Categories

Resources