Why I must use classname here in ANT? - java

<target name="run" depends="jar">
<java fork="true" classname="${main-class}">
<classpath>
<path refid="classpath"/>
<path location="${jar.dir}/${ant.project.name}.jar"/>
</classpath>
</java>
</target>
Why I cannot use something like
<java jar="build/jar/HelloWorld.jar" fork="true" >
<classpath>
<path refid="classpath"/>
<path location="${jar.dir}/${ant.project.name}.jar"/>
</classpath>
</java>
I received the error like
[java] java.lang.NoClassDefFoundError: org/apache/log4j/Logger
[java] at oata.HelloWorld.(Unknown Source)
[java] Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Logger

According to the java task documentation, your second example should just work as expected (except that the classpath will be ignored).
Edit: The information you added to your question implies a few things:
the .jar file is found
it has the correct Main-Class entry in its manifest
your application requires log4j
it does not have a correct Class-Path entry pointing to a log4j.jar file
Basically the java ant task has the same requirements as using java -jar on the command line: if your .jar file doesn't correctly run using java -jar myApp.jar on the command line, then the java Ant task won't work like that either.
Edit 2: Whenever you invoke a .jar file directly in Java, then no further classpath can be specified in any way. That's true when you use java -jar myApp.jar and it's also true when you use the java Ant task with the jar attribute. That means that the .jar file itself must have a correct Class-Path entry.

Then how java is going to know which classname you are intend to run if yopu have more than one main class and you don't have entry in manifest. Use the classname attribute to run your main class.

Related

ANT eclipse headless build - java.lang.NoClassDefFoundError

I am trying to make a headless build that requires eclipse specific tasks.
For launching the ant buildfile, I use the following command. I do it this way because I believe it allows me to run eclipse tasks that previously complained that they needed a workspace to run in. If this is incorrect/if there is a better way, please inform me.
My batch script:
java -jar %EQUINOX_LAUNCHER_JAR% -application org.eclipse.ant.core.antRunner -buildfile %ANT_SCRIPT_JAR% -data %WORKSPACE_PATH%
Inside my ant buildfile, I need to define a task:
<taskdef name="myTask" classname="path.to.class.with.execute"><classpath><pathelement location="path\to\dependency.jar"/></classpath></taskdef>
When running
<myTask/>
I get
java.lang.NoClassDefFoundError: path/to/class/that/I/tried/to/import
Classes which your task’s code uses must be in the classpath. One option is to add them explicitly to the classpath when defining the task:
<taskdef name="myTask" classname="path.to.class.with.execute">
<classpath>
<pathelement location="path/to/dependency.jar"/>
<pathelement location="path/to/transitive-dependency.jar"/>
<pathelement location="path/to/other-transitive-dependency.jar"/>
</classpath>
</taskdef>
If all the .jar files are in the same directory tree, you can shorten it to:
<taskdef name="myTask" classname="path.to.class.with.execute">
<classpath>
<fileset dir="path/to/dir" includes="**/*.jar"/>
</classpath>
</taskdef>
One other possibility is to add a Class-Path attribute to the manifest of the .jar which contains the task class. The attribute’s value is a space separated list of relative URLs, with their implied base being the .jar file where the manifest resides. For example:
Class-Path: transitive-dependency.jar utils/other-transitive-dependency.jar
If you’re building the task .jar itself in Ant, you can specify the Class-Path attribute in Ant’s jar task:
<jar destfile="task.jar">
<fileset dir="classes"/>
<manifest>
<attribute name="Class-Path"
value="transitive-dependency.jar utils/other-transitive-dependency.jar"/>
</manifest>
</jar>

Pass java compiled file as an argument to an ant target

I'm trying to use Daikon to test a large project so I needed ant to compile and run everything for me. Since I'm new to ant I'm trying to get familiar with it through a simple example given to Daikon. So, the best candidate example is the associated StackAr package with Daikon.
To run Daikon normally I will execute the following command after compiling all the java files I'm targeting.
java daikon.Chicory --daikon DataStructures.StackArTester
which is equivalent to this command
java -cp "/usr/lib/daikonparent/daikon-5.2.20/daikon.jar:." daikon.Chicory --daikon DataStructures.StackArTester
Both commands will run daikon.jar using Chicory interface with the flag --daikon and will take the StackArTester.class to instrument it and run it.
Now, my attempt to run the same command using ant looks as the following:
<project name="StackAr" default="compile" basedir=".">
<description>
simple example build file
</description>
<!-- set global properties for this build -->
<property name="src" location="DataStructures"/>
<property name="build" location="DataStructures"/>
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
</target>
<target name="compile" depends="init"
description="compile the source">
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}"
destdir="."
debug="on"
/>
</target>
<target name="run" description="run StackArTester">
<java classname="DataStructures.StackArTester">
<classpath>
<pathelement location="."/>
</classpath>
</java>
</target>
<target name="inv" description="run daikon">
<java classname="daikon.Chicory" >
<arg value="--daikon" />
<arg value="DataStructures.StackArTester"/>
<classpath>
<pathelement path="/usr/lib/daikonparent/daikon-5.2.20/daikon.jar"/>
</classpath>
</java>
</target>
<target name="clean"
description="clean up">
<!-- Delete the ${build} and ${dist} directory trees -->
</target>
</project>
The target compile is used to compile all the source files and is working. Also, the target run is used as a test to run the targeted .class file and is working. The target inv is where I'm having trouble and it's suppose to be equivalent to the two command above.
My issue is that I'm not sure how I'm suppose to pass the .calss file to Daikon. From the results I have seen I'm positive that first argument/flag --daikon is recognized. However, for the second argument DataStructures.StackArTester in most of my tires I see that it's recognized, but Daikon has an issue with its classpath. Runing the script above ant inv will generate the following error message:
Buildfile: /usr/lib/daikonparent/daikon-5.2.20/examples/java-examples/StackAr/build.xml
inv:
[java]
[java] Executing target program: java -cp /usr/share/ant/lib/ant-launcher.jar:/usr/lib/daikonparent/daikon-5.2.20/daikon.jar:/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar:/usr/lib/jvm/java-7-openjdk-amd64/lib/tools.jar:/usr/share/ant/lib/ant-testutil.jar:/usr/share/ant/lib/ant-apache-log4j.jar:/usr/share/ant/lib/ant-javamail.jar:/usr/share/ant/lib/ant-jsch.jar:/usr/share/ant/lib/ant-apache-regexp.jar:/usr/share/ant/lib/ant-antlr.jar:/usr/share/ant/lib/ant-swing.jar:/usr/share/ant/lib/ant-apache-oro.jar:/usr/share/ant/lib/ant-apache-bcel.jar:/usr/share/ant/lib/ant-apache-xalan2.jar:/usr/share/ant/lib/ant-junit.jar:/usr/share/ant/lib/ant-launcher.jar:/usr/share/ant/lib/ant-apache-bsf.jar:/usr/share/ant/lib/ant-jdepend.jar:/usr/share/ant/lib/ant-apache-resolver.jar:/usr/share/ant/lib/ant-jmf.jar:/usr/share/ant/lib/ant-commons-logging.jar:/usr/share/ant/lib/ant-commons-net.jar:/usr/share/ant/lib/ant-junit4.jar:/usr/share/ant/lib/ant.jar:/usr/lib/jvm/java-7-openjdk-amd64/lib/tools.jar -ea -Xmx1000m -javaagent:/usr/lib/daikonparent/daikon-5.2.20/java/ChicoryPremain.jar=--daikon --dtrace-file=StackArTester.dtrace.gz DataStructures.StackArTester
[java] entered daikon.chicory.Runtime.setDtrace(./StackArTester.dtrace.gz, false)...
[java] Error: Could not find or load main class DataStructures.StackArTester
[java] Chicory warning: No methods were instrumented.
[java] Warning: Did not run Daikon because target exited with 1 status
[java] Java Result: 1
BUILD SUCCESSFUL
Total time: 0 seconds
Note that the error is
Error: Could not find or load main class DataStructures.StackArTester
I'm out of ideas about what I might try. Hopefully the information above is enough. Please note that I'm in the same directory when executing the original commands and the ant command.
Thakns ...
The error
[java] Error: Could not find or load main class DataStructures.StackArTester
means that Java did not find the class DataStructures.StackArTester on your classpath.
On the line that starts with [java] Executing target program, the -cp command-line argument is your classpath. The classpath must contain a directory or jar file containing DataStructures/StackArTester.class. You just need to augment the classpath.

How to make build.xml file to run a program?

Two questions.
How do I make a build.xml file run a Java program? What are the commands?
Is there a way to run a Java program through Ant , without creating the .class files?
1- You can use a java command to run java program and create a custom task like:
<target name="run">
<java jar="build/jar/HelloWorld.jar" fork="true"/>
</target>
2- I think no, you need to comile your code before execute it, and it's not a big problem, if you use ANT. Just make a task to do that like:
<target name="compile">
<mkdir dir="build/classes"/>
<javac srcdir="src" destdir="build/classes"/>
</target>
And then you can execute a main method of custom java class, like:
<java classname="com.example.MainClass" depends="compile">
<classpath>
<pathelement path="build/classes"/>
</classpath>
</java>
Look here for a basic tutorial on Ant: https://ant.apache.org/manual/tutorial-HelloWorldWithAnt.html
As far as I know, it is impossible to run a Java program without creating .class files, as the JVM interprets .class files rather than .java files.
I think you have misunderstood the purpose of Ant. It builds Java applications, and part of this build involves compiling the .java files into .class files for you. Typically this would be so that you can deploy applications onto a server more easily.
To compile .java files using Ant, use the javac command, as in the tutorial:
<target name="compile">
<mkdir dir="build/classes"/>
<javac srcdir="src" destdir="build/classes"/>
</target>

Log4j not being added to classpath in Ant

I'm attempting to add Log4j to my project's classpath in Ant which creates an executable JAR, but it appears that it's not being added properly.
Here is the path component of my Ant build script:
<path id="classpath.compile">
<fileset dir="${dir.myLibs}">
<include name="**/*.jar"/>
</fileset>
<pathelement location="${dir.webContent}/WEB-INF/lib/log4j.jar" />
</path>
The compile target looks like this:
<target name="-compile">
<javac destdir="${dir.binaries}" source="1.6" target="1.6" debug="true" includeantruntime="false">
<src path="${dir.source}"/>
<classpath refid="classpath.compile"/>
</javac>
</target>
Tthe target that creates the JAR:
<target name="-createJar" >
<jar jarfile="${path.jarFile}"
manifest="${dir.source}\META-INF\MANIFEST.MF">
<fileset dir="${dir.binaries}" casesensitive="yes">
<exclude name="**/*.java"/>
</fileset>
</jar>
</target>
Lastly, the MANIFEST.MF:
Manifest-Version: 1.0
Class-Path: ../../../WebContent/WEB-INF/lib/log4j.jar (what is this pathing relative to?)
Main-Class: foo.Bar
The JAR is created, but when I execute it, I get:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/log4j/Logger...
Any thoughts as to what I'm doing wrong?
It looks from the classpath in your MANIFEST that you are trying to reference a jar inside your jar. The only two ways to make that work AFAIK are 1) a special classloader, like #infosec812 mentions, or 2) by exploding the jar dependencies directly into the root of your jar. Either is workable, but I don't see either of them happening in your ant script.
If you're trying to reference a jar outside of your jar, your relative classpath is relative to the location of the jar you are executing. Make sure the referenced jar exists in that location.
I'm guessing that you're running the Java program as follows
java -jar myapp.jar
In this case you'll need to specify the Class-Path attribute in the manifest. I suggest you also check out the manifestclasspath task
Creating the jar does not include the linked libraries in the jar. You would have to have the required jars in your execution classpath in order to run it that way. Or, you could use the solution I use, which is to create a one-jar archive. It adds a specialized class loader for your application into the resulting jar and also packages your required jars in to the final executable jar. It works really well for deploying neat, simple to use packages.

Problem running task using log4j using Ant

My java application uses log4j for logging. Using ant the project builds successfully, but I am unable to run it. The error I get is
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging/Log
.........
Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.Log
My classpath contains the log4j jar.
[echo] ..../apache-log4j-1.2.15/log4j-1.2.15.jar: .....
My ant version is 1.7.1. What am I missing?
[Edit] My application is referencing another project which required the commons logging jar. So I tried creating an executable jar of the referenced project so that all the dependencies are carried over. The ant task to create the executable jar is as follows:
<target name="executablejar" depends="compile">
<delete file="${dist}/app.jar" />
<javac debug="true" srcdir="${src}" destdir="${classes}" classpath="${javac.classpath}"/>
<copy todir="classes" flatten="true">
<path>
<pathelement path="${javac.classpath}"/>
</path>
</copy>
<jar jarfile="${dist}/app.jar" basedir="${classes}" />
</target>
However the error still persists. Am I creating the executable jar correctly?
You may have inadvertently imported a class from org.apache.commons.logging and now, as you might expect, the JVM is expecting to find the class definition on your classpath at runtime.
I'd recommend looking for usages of the commons-logging package in your code.
You'll have add apache commons logging to your classpath. The package org.apache.commons.logging is not part of log4j.

Categories

Resources