Pass java compiled file as an argument to an ant target - java

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.

Related

How to properly run Eclemma coverage with Java

We use non-java tests. Each one of them executes our tool which is written in Java.
I'm trying to use Eclemma for creating the coverage report of the tests.
Lets start with one test. We compile the code with build.xml. I would like somehow to create a coverage report for each test and then to merge them into one main report.
I found out that Jacoco has CMD interface I could use in order to merge those reports. But I don't understand how do I run the tool with coverage package?
Which coverage package should I use? Is it Eclemma or Jacoco?
How do I run the tool with the coverage package? Should I add it into the build.xml file? Should I add it to the command line?
I'm a bit confused about the whole idea of coverage in Java. In dynamic langues such as Python and Perl, I just execute the code with the coverage module, which creates the coverage report.
The command we use to execute out tool:
gandu -vm /usr/pkgs/java/1.6.0.25-64/bin/java -configuration /.ganduData -data /.ganduData -configuration /ganduInternalConfig --session_id 1582722179
Should I add some options?
The build in build.xml:
<target name="pde-build" depends="clean, init">
<java classname="org.eclipse.equinox.launcher.Main" fork="true" failonerror="true">
<arg value="-application" />
<arg value="org.eclipse.ant.core.antRunner" />
<arg value="-buildfile" />
<arg value="${eclipseLocation}/plugins/org.eclipse.pde.build_${pdeBuildPluginVersion}/scripts/productBuild/productBuild.xml" />
<arg value="-Dtimestamp=${timestamp}" />
<classpath>
<pathelement location="${eclipseLocation}/plugins/org.eclipse.equinox.launcher_${equinoxLauncherPluginVersion}.jar" />
</classpath>
</java>
</target>
Should I add the following command?
<arg value="-autVMArgs" />
<arg value="-Xmx800m;-XX:MaxPermSize=600M;-javaagent:${jacoco-agent-path}=destfile=${jacoco-report},append=true"/>
Update: Thanks to the two answer I have managed to create the report using the CLI. But it looks like it shows (almost) zero coverage. It shows red (uncovered) on printed lines that I see that have been executed (they were printed to the stdout).
The project contains a lot of packages but for first try I'm trying to create coverage report for a specific package. I ran:
gandu -vm /usr/pkgs/java/1.6.0.25-64/bin/java -configuration /.ganduData -data /.ganduData --session_id 1583967465 -vmargs -Xmx256m -Xms128m -javaagent:/jacoco_coverage/jacoco-0.8.5/lib/jacocoagent.jar
and then I ran:
/usr/pkgs/java/1.6.0.16-64/bin/java -jar /jacoco_coverage/jacoco-0.8.5/lib/jacococli.jar report jacoco.exec --classfiles /gandu_repo/com.core.gandu/bin/ --html temp_dir --sourcefiles /gandu_repo/com.core.gandu/src/
The output:
[WARN] Some classes do not match with execution data.
[WARN] For report generation the same class files must be used as at runtime.
[WARN] Execution data for class <PATH> does not match.
[INFO] Analyzing 8 classes.
I have trouble understanding how classfiles and sourcefiles. The file that I'm trying to get coverage on is Application. In the bin I have in some inner folder Application.class and in src I have in some inner folder Application.java. I even tried to add full path for the those files in classfiles and sourcefiles but still don't have coverage (all red). What could be the problem?
The structure of the tool:
The root contains alot of packages and each one has folder bin and src. Each src contains folders recursively with Java files. The bin has the same structure for class files.
As I know, the only place to add java agent is in the configuration of the unit tests.
Agent should be added to the JVM that executes application under test. Your confusion probably comes from the fact that usually unit tests are executed in the same JVM as code under test.
From your description unclear how JVM with the application is started.
However consider following src/Main.java as an example:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws Exception {
String input;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
input = reader.readLine();
}
if ("hello".equals(input)) {
System.out.println("Hello, World!");
}
}
}
after compilation
javac -d classes src/Main.java
This application can be executed in JVM with JaCoCo Java Agent taken from JaCoCo zip distribution as following
java -javaagent:jacoco/lib/jacocoagent.jar -cp classes Main
Then tests are executed - e.g. in this case manual input of "hello".
After graceful termination of JVM, you'll get jacoco.exec file.
By passing this jacoco.exec, source and class files to the JaCoCo Command Line Interface you can create HTML report:
java -jar jacoco/lib/jacococli.jar report jacoco.exec --classfiles classes --sourcefiles src --html report
Which coverage package should I use? Is it Eclemma or Jacoco?
EclEmma is a plugin for Eclipse IDE based on JaCoCo.
If for testing you execute your application from Eclipse IDE then you can start it with JaCoCo using EclEmma. Here is the same example executed in Eclipse IDE:
However this is not suitable for other scenarios such as Ant builds.
How do I run the tool with the coverage package? Should I add it into the build.xml file? Should I add it to the command line?
This depends on how you execute your application - if for tests your application is executed by Ant, then you can use JaCoCo Ant Tasks for configuration of agent and generation of report. As an example here is build.xml for Ant that produces the same report for src/Example.java as the above commands:
<project xmlns:jacoco="antlib:org.jacoco.ant" name="Example Ant Build with JaCoCo" default="rebuild">
<taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
<classpath path="jacoco/lib/jacocoant.jar"/>
</taskdef>
<target name="clean">
<delete dir="classes"/>
<delete dir="report"/>
<delete file="jacoco.exec"/>
</target>
<target name="compile">
<mkdir dir="classes"/>
<javac srcdir="src" destdir="classes" debug="true" includeantruntime="false"/>
</target>
<target name="run" depends="compile">
<jacoco:agent property="jacocoAgent" />
<java classname="Main" fork="true">
<classpath path="classes"/>
<jvmarg value="${jacocoAgent}"/>
</java>
</target>
<target name="report" depends="run">
<jacoco:report>
<executiondata>
<file file="jacoco.exec"/>
</executiondata>
<structure name="JaCoCo Ant Example">
<classfiles>
<fileset dir="classes"/>
</classfiles>
<sourcefiles encoding="UTF-8">
<fileset dir="src"/>
</sourcefiles>
</structure>
<html destdir="report"/>
</jacoco:report>
</target>
<target name="rebuild" depends="clean,report"/>
</project>
If application is executed by some custom homemade tool, then maybe be better to add the agent to the command line directly.

Class org.eclipse.jdt.core.JDTCompilerAdapter could not be loaded because of an invalid dependency

I am creating a java agent that will be used to to do some bytecode modification to some classes org.eclipse.jdt.core.JDTCompilerAdapter is one of them. I am using javassit to modify some the execute() method of org.eclipse.jdt.core.JDTCompilerAdapter. So I have included ecj as in my agent project (using gradle)
compile group: 'org.eclipse.jdt.core.compiler' ,name: 'ecj', version :'4.3.1'
As I need to use some classes from ecj.
The goal of the agent is to intercept the calls to execute method, modify the execute method to add some calls to some of my classes in the aim of triggering some processing.
I am testing the agent against a Simple java project with 2 classes. the project is builded with ant and uses JDTCompilerAdapter as a compiler.
Here is the build.xml file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project basedir="." default="build" name="TestProject">
<property file="build.properties" />
<property name="debuglevel" value="source,lines,vars"/>
<property name="target" value="1.7"/>
<property name="source" value="1.7"/>
<path id="PClasspath">
<pathelement location="bin"/>
</path>
<target name="init">
<mkdir dir="bin"/>
<copy includeemptydirs="false" todir="bin">
<fileset dir="src">
<exclude name="**/*.java"/>
</fileset>
</copy>
</target>
<target name="clean">
<delete dir="bin"/>
</target>
<target depends="clean" name="cleanall"/>
<target depends="init" name="build">
<javac debug="true" debuglevel="${debuglevel}" destdir="bin" includeantruntime="false" source="${source}" target="${target}">
<src path="src"/>
<classpath refid="PClasspath"/>
</javac>
</target>
<!--
<target description="copy Eclipse compiler jars to ant lib directory" name="init-eclipse-compiler">
<copy todir="${ant.library.dir}">
<fileset dir="${ECLIPSE_JDT_CORE}" includes="*.jar"/>
</copy>
</target>-->
<target name="build-e" >
<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/>
<antcall target="build"/>
</target>
The agent is to be used when building a project.
So for testing the agent I use this command:
java -jar agent-wrapper.jar --outdir ./out --exec ./build_wrapper.sh
build_wrapper.sh contains this (I have added ecj dependency so I could compile the project with JDTCompilerAdapter as I have in bulid.xml <property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/> :
../ant/bin/ant -lib ../eclipse/plugins/ecj-4.3.1.jar build-e
The idea is that the agent-wrapper will parse the argument (outdir is used to generate some stuff and exec is a script used to launch a the build of my test project) get the command to be executed from build_wrapper.sh (in this case ../ant/bin/ant -lib ../eclipse/plugins/ecj-4.3.1.jar build-e) and add it self as java agent to the command.
The problem occurs during the execution of the agent. Here is the output:
java -jar custom-agent.jar --outdir ./out --exec ./build_wrapper.sh [10:18:53]
Picked up JAVA_TOOL_OPTIONS: -javaagent:/Users/dev/TestAgent/project/custom-agent.jar=OUTDIR=/Users/dev/TestAgent/project/./out
objc[30474]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home/jre/bin/java and /Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home/jre/lib/libinstrument.dylib. One of the two will be used. Which one is undefined.
Buildfile: /Users/dev/TestAgent/project/build.xml
build-e:
init:
[mkdir] Created dir: /Users/dev/TestAgent/project/bin
build:
BUILD FAILED
/Users/dev/TestAgent/project/build.xml:47: The following error occurred while executing this line:
/Users/dev/TestAgent/project/build.xml:32: Class org.eclipse.jdt.core.JDTCompilerAdapter could not be loaded because of an invalid dependency.
Total time: 2 seconds
abnormal termination, exit code: 1
When I don't use ecj-4.3.1.jar inside my agent project, the build runs well I intercept the call to execute() method but I can't use the other classes from ecj jar.
The show stopper error is "Class org.eclipse.jdt.core.JDTCompilerAdapter could not be loaded because of an invalid dependency."
First hint at the fault might be found from reading this link
http://help.eclipse.org/mars/index.jsp?topic=%2Forg.eclipse.jdt.doc.user%2Ftasks%2Ftask-ant_javac_adapter.htm
The second hint might be that one of the jars required for running the JDTCompilerAdapter is missing.
To get the JDTCompilerAdapter to work I copied both the JDTCompilerAdapter.jar and org.eclipse.jdt.core.jar into the ant/lib folder.
There are differences based on version of eclipse and the version of java which are documented in the link mentioned above.

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>

Order of Ant Task Arguments

I'm new to Ant and wrote up a simple build.xml with some help yesterday. However after looking at the output from running ant -verbose it appears as if a class I have to handle many JUnit tests isn't being called appropriately.
<project name="JUnit_tests" default="run" basedir=".">
<!-- Define variable properties -->
<property name="src" value="${basedir}"/>
<property name="junit" value="org.junit.runner.JUnitCore"/>
<!--<property name="junit" value="org.junit.runner.JUnitCore"/>-->
<!-- Appends all jars in the current directory to the classpath -->
<path id="compile.classpath">
<fileset dir="./">
<include name="*.jar"/>
</fileset>
</path>
<!-- Compiles all code in the current directory and append to the classpath -->
<target name="compile">
<javac destdir="${src}" srcdir="${src}">
<classpath refid="compile.classpath"/>
</javac>
</target>
<!-- Runs the Test code with junit argument as long as compile was run previously -->
<target name="run" depends="compile">
<java classname="Tests" fork="true">
<arg value="${junit}"/>
</java>
</target>
My JUnit tests are in the Tests class, and I need to run the class with
java org.junit.runner.JUnitCore Tests
However based on the following output I believe it's being called as
java Tests org.junit.runner.JUnitCore
Ant -verbose output:
run:
[java] Executing '/usr/lib/jvm/java-6-sun-1.6.0.26/jre/bin/java' with arguments:
[java] 'Tests'
[java] 'org.junit.runner.JUnitCore'
[java]
[java] The ' characters around the executable and arguments are
[java] not part of the command.
[java] Exception in thread "main" java.lang.NoSuchMethodError: main
[java] Java Result: 1
Any ideas? I've been doing research but couldn't find much about the order of arguments, specifically with a java call. Thanks!
You have interverted your argument (which is Tests) and the main class which is org.junit.runner.JUnitCore.
<arg> are the arguments of the program
<jvmarg> are the arguments of the JVM
In between the two of them, you will have the main class.
Java usage:
Usage: java [-options] class [args...]
In your case, you want to execute the main method of org.junit.runner.JUnitCore and the arguments passed to that main method should be Tests

Why I must use classname here in ANT?

<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.

Categories

Resources