Link to home
Start Free TrialLog in
Avatar of dleehanson
dleehansonFlag for United States of America

asked on

Running Eclipse Project as an Executable Jar

I am looking for some help in getting my eclipse project to run as an executable jar.  The problem is that the aforementioned project has many other jar and file dependencies which I don't know how to set up via the command line.  Eclipse lets me export my project as an executable jar, but I can't seem to get it to work.  I keep getting ClassNotFoundErrors.  

Does anyone have any tips for how to do this with the least amount of pain?  I was thinking I could maybe write a batch file since I'm guessing that the command is going to get pretty long.  It's been awhile since I have run anything via the command line though, so examples would be very helpful.

In the end I just need to get my command line-based application to run.  It works in the Eclipse ide, but I need it to run standalone.  Thanks in advance for any and all help.

--Charly
Here is what I have tried so far:
 
C:\temp
   myJar.jar
   config.xml
C:\temp\lib
        required jar files
        required dll
C:\temp\resources
        log4j.properties
        config.xsd
C:\temp\resources\package...
                  resource.properties
 
Command Line Arguments
c:\java -classpath C:\temp;C:\temp\lib;C:\temp\resources -jar myJar.jar

Open in new window

Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

Please post the errors you're gettings
Oh and can you extract the manifest from the main jar and post it here
Avatar of dleehanson

ASKER

I'm guessing that the problem is with my manifest file.  What all has to be in there?

Thanks for the help.

--Charly
       
When I try and run the jar with the above cmd I get:
Exception in thread "main" java.lang.NoClassDefFoundError:javafish/clients/opc/exception/CoInitializeException
 
My manifest file is just this:
Manifest-Version: 1.0
Main-Class: com.pcielectric.amc.AMCLabelServer

Open in new window

Here is my .classpath contents as well.  Is this an Eclipse-only thing, or is this used by the jar?
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
	<classpathentry excluding="com/pcielectric/amc/label/AMCLabelServerWithXML.java|com/pcielectric/amc/ServerThread.java" kind="src" path="src"/>
	<classpathentry excluding="com/pcielectric/amc/AMCProductionLineTest.java|com/pcielectric/amc/ServerThreadTest.java" kind="src" path="test"/>
	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
	<classpathentry kind="lib" path="lib/commons-logging-1.1.jar"/>
	<classpathentry kind="lib" path="lib/jdom.jar"/>
	<classpathentry kind="lib" path="lib/log4j-1.2.15.jar"/>
	<classpathentry kind="lib" path="resources"/>
	<classpathentry kind="lib" path="lib/filemonitor.jar"/>
	<classpathentry kind="lib" path="lib/jeasyopc.jar"/>
	<classpathentry kind="output" path="bin"/>
</classpath>

Open in new window

There should be a

Class-Path: lib/jdom.jar lib/filemonitor.jar .............

entry in the manifest with all the paths in. Note the separators are spaces
I'm heading down the jar trail atm so I can ask more intelligent questions.  I've never made jars or worked with their manifests...
I know Eclipse doesn't integrate very well with Ant, but i would have thought it could make a better job of exporting it. Are you sure you're doing it right?
Actually, having said that about Ant, it might not even be using it, so don't take that bit too seriously ;-)
No, I'm not sure I'm doing it right... :(

I have heard of Ant, but I'm not really familiar with what it does.  Is it something along the lines of what I am trying to do?

It looks like it is installed in my Eclipse install, but I'm not using it.
I tried exporting my project using Ant, and this is what I got.  I'm not sure what to do with it now though to create my executable jar file...
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- WARNING: Eclipse auto-generated file.
              Any modifications will be overwritten.
              To include a user specific buildfile here, simply create one in the same
              directory with the processing instruction <?eclipse.ant.import?>
              as the first entry and export the buildfile again. -->
<project basedir="." default="build" name="AMCLabeler">
    <property environment="env"/>
    <property name="ECLIPSE_HOME" value="../../target/eclipse"/>
    <property name="debuglevel" value="source,lines,vars"/>
    <property name="target" value="1.6"/>
    <property name="source" value="1.6"/>
    <path id="AMCLabeler.classpath">
        <pathelement location="bin"/>
        <pathelement location="lib/commons-logging-1.1.jar"/>
        <pathelement location="lib/jdom.jar"/>
        <pathelement location="lib/log4j-1.2.15.jar"/>
        <pathelement location="resources"/>
        <pathelement location="lib/filemonitor.jar"/>
        <pathelement location="lib/jeasyopc.jar"/>
    </path>
    <target name="init">
        <mkdir dir="bin"/>
        <copy includeemptydirs="false" todir="bin">
            <fileset dir="src" excludes="**/*.launch, **/*.java"/>
        </copy>
    </target>
    <target name="clean">
        <delete dir="bin"/>
    </target>
    <target depends="clean" name="cleanall"/>
    <target depends="build-subprojects,build-project" name="build"/>
    <target name="build-subprojects"/>
    <target depends="init" name="build-project">
        <echo message="${ant.project.name}: ${ant.file}"/>
        <javac debug="true" debuglevel="${debuglevel}" destdir="bin" source="${source}" target="${target}">
            <src path="src"/>
            <exclude name="com/pcielectric/amc/label/AMCLabelServerWithXML.java"/>
            <exclude name="com/pcielectric/amc/ServerThread.java"/>
            <classpath refid="AMCLabeler.classpath"/>
        </javac>
    </target>
    <target description="Build all projects which reference this project. Useful to propagate changes." name="build-refprojects"/>
    <target description="copy Eclipse compiler jars to ant lib directory" name="init-eclipse-compiler">
        <copy todir="${ant.library.dir}">
            <fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar"/>
        </copy>
        <unzip dest="${ant.library.dir}">
            <patternset includes="jdtCompilerAdapter.jar"/>
            <fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar"/>
        </unzip>
    </target>
    <target description="compile project with Eclipse compiler" name="build-eclipse-compiler">
        <property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/>
        <antcall target="build"/>
    </target>
    <target name="AMCApplicatorTest">
        <java classname="AMCApplicatorTest" failonerror="true" fork="yes">
            <classpath refid="AMCLabeler.classpath"/>
        </java>
    </target>
    <target name="AMCLabelServer">
        <java classname="com.pcielectric.amc.AMCLabelServer" failonerror="true" fork="yes">
            <classpath refid="AMCLabeler.classpath"/>
        </java>
    </target>
    <target name="AMCLabelServerWithXML">
        <java classname="com.pcielectric.amc.label.AMCLabelServerWithXML" failonerror="true" fork="yes">
            <classpath refid="AMCLabeler.classpath"/>
        </java>
    </target>
    <target name="AMCLabelTest">
        <java classname="com.pcielectric.amc.AMCLabelTest" failonerror="true" fork="yes">
            <classpath refid="AMCLabeler.classpath"/>
        </java>
    </target>
    <target name="AMCOrderTest">
        <java classname="com.pcielectric.amc.AMCOrderTest" failonerror="true" fork="yes">
            <classpath refid="AMCLabeler.classpath"/>
        </java>
    </target>
    <target name="AMCPalletTest">
        <java classname="com.pcielectric.amc.AMCPalletTest" failonerror="true" fork="yes">
            <classpath refid="AMCLabeler.classpath"/>
        </java>
    </target>
    <target name="AMCXMLTest">
        <java classname="com.pcielectric.learning.AMCXMLTest" failonerror="true" fork="yes">
            <classpath refid="AMCLabeler.classpath"/>
        </java>
    </target>
    <target name="DateFormatTest">
        <java classname="com.pcielectric.learning.DateFormatTest" failonerror="true" fork="yes">
            <classpath refid="AMCLabeler.classpath"/>
        </java>
    </target>
    <target name="FileManipTest">
        <java classname="com.pcielectric.learning.FileManipTest" failonerror="true" fork="yes">
            <classpath refid="AMCLabeler.classpath"/>
        </java>
    </target>
    <target name="FormatTest">
        <java classname="com.pcielectric.learning.FormatTest" failonerror="true" fork="yes">
            <classpath refid="AMCLabeler.classpath"/>
        </java>
    </target>
    <target name="JDomTest">
        <java classname="com.pcielectric.learning.JDomTest" failonerror="true" fork="yes">
            <classpath refid="AMCLabeler.classpath"/>
        </java>
    </target>
    <target name="MorePrinting">
        <java classname="com.pcielectric.learning.MorePrinting" failonerror="true" fork="yes">
            <classpath refid="AMCLabeler.classpath"/>
        </java>
    </target>
    <target name="OPCTest">
        <java classname="com.pcielectric.learning.OPCTest" failonerror="true" fork="yes">
            <classpath refid="AMCLabeler.classpath"/>
        </java>
    </target>
    <target name="PrintingTest">
        <java classname="com.pcielectric.learning.PrintingTest" failonerror="true" fork="yes">
            <classpath refid="AMCLabeler.classpath"/>
        </java>
    </target>
    <target name="ServerThreadTest">
        <java classname="com.pcielectric.amc.ServerThreadTest" failonerror="true" fork="yes">
            <classpath refid="AMCLabeler.classpath"/>
        </java>
    </target>
    <target name="XMLTesting">
        <java classname="com.pcielectric.learning.XMLTesting" failonerror="true" fork="yes">
            <classpath refid="AMCLabeler.classpath"/>
        </java>
    </target>
    <target name="ZebraPrinterTest">
        <java classname="com.pcielectric.amc.ZebraPrinterTest" failonerror="true" fork="yes">
            <classpath refid="AMCLabeler.classpath"/>
        </java>
    </target>
</project>

Open in new window

Wow - more targets than at an international archery convention. Luckily you can use the default. Change to the directory in which the file build.xml resides and do

ant

at the command line
Hang on - there aren't *enough* targets. There's no distribution target. You haven't selected the right options for an executable jar (if they exist). When you have, you should be able to search on

<jar

in there and find something. Keep trying ..
I think I am running into too many options.  While Ant looks cool, I think I was close to getting it to work with my new manifest file I was working with.  Or do you think that Ant is just going to be better and I should abandon this route?

After adding the classpaths, I got a new error.  I think the DataConversionException is from the jar not being able to find my labelerConfig.xml file which is outside of the jar.  I need it to be outside the jar since the user needs to change it from time to time.  Do you know how to reference a file outside of the jar?
C:\Documents and Settings\Charly\Desktop>java -jar amc.jar
Exception in thread "main" java.lang.NoClassDefFoundError: org/jdom/DataConversi
onException
Caused by: java.lang.ClassNotFoundException: org.jdom.DataConversionException
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClassInternal(Unknown Source)

Open in new window

The jdom jar is not in the classpath. Again, if you post the manifest of amc.jar here, it will help. But you're getting somewhere ...
I thought I had the jdom.jar listed in there...  They are space separated right?  It's not liking the filename for some reason, but I just checked and the name is right.  Can you see anything that I'm doing wrong?  When I entered it in I had it all on one line since I didn't know how to do line continuation.  It looks like it bumped it down to the next line for me.
Manifest-Version: 1.0
Class-Path: lib/commons-logging-1.1.jar lib/jdom.jar lib/log4j-1.2.15.
 jar lib/filemonitor.jar lib/jeasyopc.jar javafish/clients/opc javafis
 h/clients/opc/lang ./ 
Main-Class: com.pcielectric.amc.AMCLabelServer

Open in new window



jdom.jar must be in a lib directory, sitting below where your executable jar is located. Is it?
Are you talking outside the jar or inside it?  I have a directory called lib inside the jar containing all the jars I need.  Or does it have to be outside of it?
Yes it has to be outside of it. Jars can't be nested
I'm still running into the same problem.  How about I send you a copy of my file structure?  Maybe it would be easier for you to show me what I am doing wrong?

Thank you for your continued help on all this I really appreciate it.

--Charly
temp.txt
OK - i'll probably need build.xml too
I can't test this, since i only have 1.5 and you've used 1.6, but give it a go. Put it in the parent directory of lib
amc2.jar.txt
Sure thing.
build.txt
OK!  We're getting close!  My program is having trouble finding my labelingConfig.xml file.  When using eclipse I just had it in the project root, and referenced it like so:


public static final String LABELING_CONFIG_FILE = "labelingConfig.xml";
 
inside main()...
 
    configDoc = builder.build(LABELING_CONFIG_FILE);
 
I thought that since it is in the root along with the jar that it would find it, but it looks like it can't.  Any ideas?

Open in new window

Also, what did you change to get it to work?  I couldn't see any differences in the manifest.  Was there something I overlooked in the file structure?
The manifest in amc.jar had no Class-Path at all

What type is 'builder'?
ASKER CERTIFIED SOLUTION
Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I must have overwritten my modded manifest file during one of my exports. :(

Builder is of type SaxBuilder from jdom
public static void main(String[] args)
{		
	//Configure logging setup (updates every 10sec)
	PropertyConfigurator.configureAndWatch(LOG4J_CONFIG_FILE, 10000);
		
	try
	{			
		// Build the document with SAX and Xerces with validation
		SAXBuilder builder = new SAXBuilder(true);
			
		builder.setFeature("http://apache.org/xml/features/validation/schema", true);
			
		// Create the document
		configDoc = builder.build(LABELING_CONFIG_FILE);
			
		//----------------------------------------------	
		// Get our opcClient parameters
		Element opcClient = configDoc.getRootElement().getChild("opcClient");
		String host = opcClient.getChildText("host");
		String progId = opcClient.getChildText("serverProgId");
		String handle = opcClient.getChildText("serverClientHandle");
			
		//Create our new JEasyOpc server
		logger.debug("Creating new JEasyOpc('" + host + "', '" + progId + "', '" + handle + "').");
		jopc = new JEasyOpc(host, progId, handle);
 
etc...

Open in new window

I got it to work!  In my xml file I was referencing the schema as in ./resources/labelingConfig.xml since that is how it was in my Eclipse project.  When exporting my project, it seems Eclipse decided not to make the resources folder.  I changed it to the lib folder and everything works.  Now I just have to make a little bat file to run that command and I should be good to go.

Thanks so much CEHJ.  You made my day.  Here are your points.  Well-earned I might add. :)

--Charly
:-)
Very speedy help.  Awesome.