bundled executable jar file - couldnot find main class - java

I am trying to execute a jar file StartupUtil.jar but it's giving an error of Couldnot find and load main class. I looked at other similar question and tried but couldnot figure out what is wrong.
My structure for created StartupUtil.jar is
->com.ihc.startup.util.StartupService
->META-INF/MANIFEST.MF
The content of MANIFEST is:
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.9.2
Created-By: 1.7.0_79-b15 (Oracle Corporation)
Main-Class: com.ihc.startup.util.StartupService
Class-Path: C:\Users\tgupta12\workspace_new\IHC_Startup\lib\bson-3.0.1
.jar C:\Users\tgupta12\workspace_new\IHC_Startup\lib\mongodb-driver-3
.0.1.jar C:\Users\tgupta12\workspace_new\IHC_Startup\lib\mongodb-driv
er-core-3.0.1.jar C:\Users\tgupta12\workspace_new\IHC_Startup\classes
Here is my build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="Startup" default="build" basedir=".">
<property file="./build.properties" />
<path id="lib-classpath">
<fileset dir="${libApp.dir}">
<include name="*.jar"/>
</fileset>
<pathelement path="${bin.dir}"/>
</path>
<target name="build" description="Compile main source tree java files">
<echo message=" Build Startup Utility" />
<mkdir dir="${bin.dir}"/>
<echo message=" Compiling source files" />
<javac destdir="${bin.dir}" source="${versionJDK}" target="${versionTarget}" debug="true"
deprecation="false" optimize="false" failonerror="true" includeantruntime="false">
<src path="${src.dir}"/>
<classpath refid="lib-classpath"/>
</javac>
<echo message=" ...Compilation of source files OK" />
<echo message=" Generating JAR for Startup - StartupUtility.jar" />
<delete file="${out.dir}/${startup-util-name}" />
<!-- convert classpath to a flat list/string -->
<pathconvert property="lib.classpath" pathsep=" ">
<path refid="lib-classpath" />
<!--<flattenmapper />-->
</pathconvert>
<jar destfile = "${out.dir}/${startup-util-name}" basedir = "${bin.dir}" includes = "**/*">
<manifest >
<attribute name="Class-Path" value="${lib.classpath}" />
<attribute name="Main-Class" value="com.ihc.startup.util.StartupService"/>
</manifest>
</jar>
<echo message=" ...JAR Created for Startup" />
</target>
<target name="run" depends="build">
<java jar="${out.dir}/${startup-util-name}" fork="true"/>
</target>
Below is my build.properties file:
#Directories
build.dir=build
src.dir=src
libApp.dir=lib
out.dir=out
web.dir=WebContent/WEB-INF
bin.dir=classes
webcontent.dir=WebContent
#File Name
war-file-name=StartupService.war
startup-util-name=StartupUtil.jar
#Target Properties
versionJDK=1.7
versionTarget=1.7
When it tries to execute the target run it gives
Error: Could not find or load main class com.ihc.startup.util.StartupService

I strongly suspect that the problem is it can't find the dependencies, which means it can't properly load the main class. I've never seen absolute filenames given in a manifest before, nor am I convinced about how you're breaking the lines (although that may be valid). Given how unportable it is to use the absolute filenames, I strongly suggest you just use relative ones.
Change your manifest to just:
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.9.2
Created-By: 1.7.0_79-b15 (Oracle Corporation)
Main-Class: com.ihc.startup.util.StartupService
Class-Path: bson-3.0.1.jar mongodb-driver-3.0.1.jar mongodb-driver-core-3.0.1.jar
Then put those jar files in the same directory as StartupUtil.jar.

Related

Javac cannot find SWT library despite correct classpath

I have a Java project that uses SWT and compiles/runs perfectly.
When I try to compile via Ant, however, javac cannot find the SWT library despite the build.xml specifying the correct classpath.
The SWT library is located in C:\my_work\Eclipse\3.6-64\plugins\. As seen below (under the javac tags, this classpath is specified as such.
build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project default="run" name="My Project">
<target name="run" depends="compile">
<java classname="com.company.program.project">
<classpath path="staging\" location="C:\my_work\Eclipse\3.6-64\plugins\"/>
</java>
</target>
<target name="compile">
<javac includeantruntime="false" srcdir="./src" destdir="staging">
<classpath path="C:\my_work\Eclipse\3.6-64\plugins\"></classpath>
</javac>
</target>
<jar destfile="./build/jars/swtgui.jar" filesetmanifest="mergewithoutmain">
<manifest>
<attribute name="Main-Class" value="org.swtgui.MainGui" />
<attribute name="Class-Path" value="." />
</manifest>
<fileset dir="./bin/com/company/program/project" includes="**/*.class" />
<fileset dir="C:\my_work\Eclipse\3.6-64\plugins\" includes="org.eclipse.swt.win32.win32.x86_64_3.6.0.v3650b.jar" />
</jar>
<record name="./MyProject.log" loglevel="verbose" action="start"/>
The above gives me errors on import statements such as the following:
error: package org.eclipse.swt does not exist
import org.eclipse.swt.SWT;
^
Why does javac not find the SWT library when the classpath is correctly specified?
Also how can I find out where javac is looking? The logs -- even in verbose mode -- tell me nothing about where javac is trying to find these import statements.
SWT provides a separate Jar for standalone Java applications.
You can download the latest one from here - look at the 'SWT Binary and Source' section near the bottom of the page.
it seems <classpath path="C:\my_work\Eclipse\3.6-64\plugins\"></classpath> is not adding dependencies to compile classpath
this way works for me:
<target name="compile">
<javac includeantruntime="false" srcdir="./src" destdir="staging">
<classpath>
<fileset dir="C:\my_work\Eclipse\3.6-64\plugins">
<!-- <include name="**/*.jar" /> -->
<include name="org.eclipse.swt.*.jar" />
</fileset>
</classpath>
</javac>
</target>

java.lang.NoClassDefFoundError + ant - running a jar

Tagging- Selenium as well just in case someone faced similar issue while creating selenium tests using Ant.
I have seen lot of questions/answers on this topic, tried all the options suggested on various forums but still my issue is not getting resolved. Basically i compile code(includes the test scripts), create JAR and run the same JAR. For some reason it does not seem to identify the libraries during run time. Same code(With tests) works fine when main() method is run from Eclipse. Here is the build.xml,
<project default="run">
<target name="clean">
<delete dir="build" />
</target>
<target name="init-classpath">
<path id="lib.classpath">
<fileset dir="./lib/">
<include name="**.jar" />
</fileset>
</path>
<pathconvert property="mf.classpath" pathsep=" ">
<path refid="lib.classpath" />
<flattenmapper />
</pathconvert>
</target>
<target name="jar" depends="clean, init-classpath">
<javac classpathref="lib.classpath" destdir="./compiled" failonerror="true" srcdir="./src" />
<mkdir dir="build/jar" />
<jar destfile="build/jar/BANC.jar" basedir="compiled">
<manifest>
<attribute name="Main-Class" value="com.portico.driver.TestDriver" />
<attribute name="Class-Path" value="${mf.classpath}" />
</manifest>
</jar>
</target>
<target name="run" depends="jar">
<java jar="build/jar/BANC.jar" fork="true">
</java>
</target>
</project>
Error:-Exception in thread "main" java.lang.NoClassDefFoundError: jxl/Workbook
Manifest content
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.3
Created-By: 1.6.0_41-b02 (Sun Microsystems Inc.)
Main-Class: com.portico.driver.TestDriver
Class-Path: activation.jar commons-lang-2.4.jar jna-3.4.0.jar jxl.jar
logging-selenium-1.2.jar mail.jar ojdbc14.jar poi-3.0.2-FINAL.jar rep
ortng-1.1.1.jar saxon-8.7.jar selenium-grid-demo-1.0.7.jar selenium-g
rid-demo-standalone-1.0.7.jar selenium-grid-hub-1.0.7.jar selenium-gr
id-hub-standalone-1.0.7.jar selenium-grid-remote-control-1.0.7.jar se
lenium-grid-remote-control-standalone-1.0.7.jar selenium-grid-tools-1
.0.7.jar selenium-grid-tools-standalone-1.0.7.jar selenium-server-1.0
.3-standalone.jar selenium-server-standalone-2.33.0.jar sikuli-script
.jar testng-6.8.jar velocity-1.7.jar
The first thing to check is, whether the problem is connected with the manifest or something else. If you can run your application with java -cp <allthejarfiles> <main-class> the problem is connected with the manifest. Keep in mind that the jar files specified in the manifest are relative to the jar file’s location. Trying to run the application with the -verbose:class option gives hint about which jar are really loaded.
Your manifest assumes the jars in the current working directory. So it would require dir attribute set to the folder where the jar exists.
Java task supports providing classpath in the arguments. Try giving the classpath in arguments.
<target name="run" depends="jar">
<java jar="build/jar/BANC.jar" fork="true" dir="build/jar" >
<classpath>
<pathelement path="${lib.classpath}"/>
</classpath>
</java>
</target>
I have faced the same issue in my project. I suggest that you should create a separate directory specially for the jar files, put all of your jars in that directory, and then point the lib address to that directory.
for example in your case say I have created a directory D:/jar_collection, where I have put all my jars physically.
<property name="lib.dir" value="D:/jar_collection"/>
<target name="setClassPath">
<path id="classpath_jars">
<fileset dir="${lib.dir}" includes="*.jar" />
</path>
<pathconvert pathsep=":" property="test.classpath" refid="classpath_jars" />
</target>
and it works fine. Please try it once.

Using Ant's classpath in Eclipse

I have an Ant build.xml file that works just fine on the command line: it compiles, builds the JAR, and I am able to execute the main method from the JAR just fine. The build.xml file references several thirdparty libraries that are scattered here and there. When building the JAR, the script doesn't include all the thirdparty libraries into the JAR itself. Instead, it puts their path into the JAR's manifest. This helps to keep my JAR slim and tidy.
I'd like to be able to edit and debug my project in Eclipse, but I can't find an easy way to do so. I can have my project use the Ant file to build the project, and that seems to work. However, Eclipse is having trouble finding the thirdparty libaries, and thus Eclipse is having two problems:
it shows (in the text editor) lots of compile errors, because
lots of classes are undefined, and
it can't execute the JAR.
I can solve both of the above problems by specifying by hand, in two difference places (i.e., the build path via Properties->Java Build Path->Libraries, and the execution classpath via Run Configurations->Classpath), all the third party libraries. But it seems like I shouldn't have to do this manually, since all the third party libraries are already listed in my JAR's manifest. What am I doing wrong?
Here's my build.xml file:
<!-- Set global properties for this build -->
<property name="src" location="./src" />
<property name="build" location="./build"/>
<property name="dist" location="./dist"/>
<property name="logs" location="./logs"/>
<property name="docs" location="./docs"/>
<property name="jar" location="${dist}/dynamic_analyzer.jar"/>
<property name="lib" location="../../thirdparty/lib"/>
<property name="hive-util" location="../../hive-utils/dist"/>
<property name="hpdb" location="../../hive-db/hpdb/dist"/>
<property name="static" location="../../hive-backend/static_analyzer/dist"/>
<property name="mainclass" value="com.datawarellc.main.DynamicMain"/>
<path id="dep.runtime">
<fileset dir="${lib}" includes="**/*.jar"/>
<fileset dir="${hive-util}" includes="**/*.jar"/>
<fileset dir="${hpdb}" includes="**/*.jar"/>
<fileset dir="${static}" includes="**/*.jar"/>
</path>
<target name="clean">
<delete dir="${build}"/>
<delete dir="${dist}"/>
<delete dir="${docs}"/>
<delete dir="${logs}"/>
</target>
<target name="init">
<tstamp/>
<mkdir dir="${build}"/>
<mkdir dir="${dist}"/>
<mkdir dir="${logs}"/>
</target>
<target name="compile" depends="init">
<javac srcdir="${src}" destdir="${build}" debug="on" includeantruntime="false">
<classpath refid="dep.runtime" />
</javac>
<!-- Debug output of classpath -->
<property name="myclasspath" refid="dep.runtime"/>
<echo message="Classpath = ${myclasspath}"/>
</target>
<target name="jar" depends="compile">
<!-- Put the classpath in the manifest -->
<manifestclasspath property="manifest_cp" jarfile="${jar}" maxParentLevels="10">
<classpath refid="dep.runtime" />
</manifestclasspath>
<jar jarfile="${jar}" basedir="${build}">
<manifest>
<attribute name="Main-Class" value="${mainclass}"/>
<attribute name="Class-Path" value="${manifest_cp}"/>
</manifest>
<zipfileset dir="${src}" includes="**/*.xml" />
</jar>
</target>
You can see that I have third-party libraries in several directories (${lib}, ${hive-util}, ${hpdb}, and ${static}). I use these to create a path called dep.runtime. I then include dep.runtime in the manifest when building my jar. How can I get Eclipse to use the same dep.runtime for the build path and the classpath when executing?
An alternative to perl is to use an embedded groovy task:
<project name="demo" default="eclipse-files">
<property name="src.dir" location="src"/>
<property name="classes.dir" location="build/classes"/>
<path id="dep.runtime">
<fileset dir="${lib}" includes="**/*.jar"/>
<fileset dir="${hive-util}" includes="**/*.jar"/>
<fileset dir="${hpdb}" includes="**/*.jar"/>
<fileset dir="${static}" includes="**/*.jar"/>
</path>
<target name="bootstrap">
<mkdir dir="${user.home}/.ant/lib"/>
<get dest="${user.home}/.ant/lib/groovy-all.jar" src="http://search.maven.org/remotecontent?filepath=org/codehaus/groovy/groovy-all/2.1.4/groovy-all-2.1.4.jar"/>
</target>
<target name="eclipse-files">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy"/>
<groovy>
import groovy.xml.MarkupBuilder
project.log "Creating .classpath"
new File(".classpath").withWriter { writer ->
def xml = new MarkupBuilder(writer)
xml.classpath() {
classpathentry(kind:"src", path:properties["src.dir"])
classpathentry(kind:"output", path:properties["classes.dir"])
classpathentry(kind:"con", path:"org.eclipse.jdt.launching.JRE_CONTAINER")
project.references."dep.runtime".each {
classpathentry(kind:"lib", path:it)
}
}
}
</groovy>
</target>
<target name="clean">
<delete file=".classpath"/>
</target>
</project>
Notes:
The bootstrap target will download the 3rd party groovy jar (No dependency on perl)
Groovy can access the "dep.runtime" ANT path directly and iterate over its contents
Groovy has excellent support for writing XML files.
The following answer is similar and additionally generates the Eclipse .project file.
Using Apache Ivy with netbeans
I came up with the following workaround, inspired by the link provided by #leeand00.
First, I wrote a simple Perl script (called genClasspath.pl) that generates the .classpath file that Eclipse uses.
#!/usr/bin/perl
use strict;
if (#ARGV != 2) {
print STDERR "Usage: $0 OUTFILE CLASSPATHSTRING\n";
print STDERR "e.g., $0 .classpath path1:path2:path3\n";
exit 1;
}
my $OUTFILE = $ARGV[0];
my $CLASSPATHSTRING = $ARGV[1];
open my $out_fh, '>', $OUTFILE or die "Couldn't open output file: $!";
print $out_fh q{<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="output" path="build"/>
};
my #libs = split(":", $CLASSPATHSTRING);
foreach my $thisLib (#libs){
print $out_fh " <classpathentry kind=\"lib\" path=\"$thisLib\"/>\n";
}
print $out_fh "</classpath>\n";
Then, I have my build.xml file call this script with the content of dep.runtime:
<target name="compile" depends="init">
<javac srcdir="${src}" destdir="${build}" debug="on" includeantruntime="false">
<classpath refid="dep.runtime" />
</javac>
<property name="myclasspath" refid="dep.runtime"/>
<exec dir="." executable="../../scripts/genClasspath.pl" os="Linux">
<arg value=".classpath"/>
<arg value="${myclasspath}"/>
</exec>
</target>
The only catch is that I need to run Ant on the command line at least once before I open the project in Eclipse. But when I do, Eclipse is able to compile and execute my project just fine, since the classpath is exactly the same as Ant's.

NoClassDefFound error for a jar created using ant build

I have a java project with class having main method in package com.nik.mypackage. Only one library is referenced which is someLib-5.0.2.jar
This library is in lib folder in eclipse and added to the build path.
I am creating executable jar of the application using the below ant script target:
<property name="src" location="src"/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>
<target name="init">
<tstamp/>
<mkdir dir="${build}"/>
</target>
<target name="compile" depends="init"
description="compile the source " >
<javac srcdir="${src}" destdir="${build}">
<classpath>
<pathelement path="${classpath}"/>
<pathelement location="lib/someLib-5.0.2.jar"/>
</classpath>
</javac>
</target>
<target name="dist" depends="compile" description="generate the distribution" >
<!-- Create the distribution directory -->
<mkdir dir="${dist}/lib"/>
<copy todir="${build}/lib" verbose="true" file="lib/someLib-5.0.2.jar" />
<!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
<jar jarfile="${dist}/lib/myProject-${DSTAMP}.jar" basedir="${build}">
<manifest>
<attribute name="Main-Class" value="com.nik.mypackage.MainClass"/>
<attribute name="Class-Path" value="../lib/someLib.jar"/>
</manifest>
</jar>
</target>
The jar MyProject-20111126.jar is getting created. However, running the below command:
c:>java -jar MyProject-20111126.jar
is throwing a NoClassDefFoundError for a class in someLib.jar
What am I doing wrong ??
Thanks for reading!
When you run where is someLib.jar relative to the MyProject-20111126.jar?
The classpath you are setting up in the MyProject.jar is telling the VM to look for a lib folder in the parent directory of MyProject.jar.
The ClassPath entry in the manifest is interpreted relative to the location of the JAR file. It is used to locate jar files on the File System. The regular class loader in JAVA does not support JAR files bundled inside of JAR files.
As mentioned in the comment by Eric Rosenberg, we can not nest jar files inside other jar files. So we need to deflat the library and bundle individual classes in the app jar.

How to build a jar using an own MANIFEST.MF in Eclipse

I have a custom MANIFEST.MF in my java-project in Eclipse.
When exporting the project to a jar, I choose
Use existing manifest from workspace
Extracting the .jar shows that eclipse generated its own manifest.
My manifest:
Manifest-Version: 1.0
Main-Class: de.somehow.tagPDF.Main
Class-Path: lib/iText-5.0.2.jar;lib/jxl.jar;lib/jai_codec.jar;lib/jai_core.jar
How can I fix this?
You can make use of a build.xml to build the jar file for you.
Then you just run the build.xml as a Ant task.
See
If you want the build.xml to run automatically every time you build your Eclipse project, you can add it to the Builders list.
See
Below is a sample build.xml where a custom manifest is used:
<?xml version="1.0" encoding="UTF-8"?>
<project basedir="." name="Example" default="run_build">
<property name="guiJar" value="../../Library/<jar-name>.jar"></property>
<target name="run_build" depends="delete_old_jar,create_dirs,create_manifest,copy_all_class_files,create_jar,delete_temp_dirs">
</target>
<target name="delete_old_jar">
<delete file="${guiJar}">
</delete>
</target>
<target name="create_dirs">
<mkdir dir="jar_temp" />
<mkdir dir="jar_temp/META-INF" />
</target>
<target name="delete_temp_dirs">
<delete dir="jar_temp">
</delete>
</target>
<target name="create_manifest">
<manifest file="jar_temp/META-INF/MANIFEST.MF">
<attribute name="Manifest-Version" value="1.0" />
<attribute name="Version" value="1.0.0" />
<attribute name="Company" value="Value" />
<attribute name="Project" value="Value" />
<attribute name="Java-Version" value="${java.version}" />
<attribute name="Class-Path" value="test.jar" />
<attribute name="Main-Class" value="com.Main" />
</manifest>
</target>
<target name="create_jar">
<jar destfile="${guiJar}" manifest="jar_temp/META-INF/MANIFEST.MF" basedir="jar_temp">
</jar>
</target>
<target name="copy_all_class_files">
<copy todir="jar_temp">
<fileset dir="classes">
<include name="*/**" />
</fileset>
</copy>
</target>
</project>
In eclipse 3.6.1.
Rigth click on your compiled project -> Export
Next you should choose Java - JAR File from the tree
In new form appeared after you select options don't click finish but 'Next'.
Third form will be 'JAR Manifest Specification' and there you can choose your manifest file instead of eclipse generated one.

Categories