I actualy have 2 problems
I use eclipse -> export project to generate a jar file for my simple desktop (GUI) program
It generates a jar file and an ant script.
first problem:
the generated jar works fine when double-clicked.
When I use the generated ant script to generate the jar
by myself, it doesn't work.
What can be wrong with a target like this (assuming that all dependencies are met)
<target name="create_run_jar">
<jar destfile="G:/dev/myproj/myproj.jar">
<manifest>
<attribute name="Main-Class" value="view.myproj"/>
<attribute name="Class-Path" value=". myproj_lib/grouplayout.jar"/>
</manifest>
<fileset dir="G:/dev/myproj/bin"/>
</jar>
<delete dir="G:/dev/myproj/myproj_lib"/>
<mkdir dir="G:/dev/myproj/myproj_lib"/>
<copy file="G:/dev/.metadata/.plugins/org.dyno.visual.swing/layoutext/grouplayout.jar" todir="G:/dev/myproj/myproj"/>
</target>
//nevemind
//Second problem:
//when I double click on the auto-generated jar file the program launches and works fine.
//when I do java myjar from the command-line I get main class not found exception..
//weird huh?
I suggest that you take the JAR files generated the two ways, use the jar command to expand them into temporary directories, and then use diff in recursive mode to compare them.
However, I suspect that #Pace has put his finger on the problem; i.e. that you are using relative paths in the Class-Path manifest entry and this is liable to cause problems.
java -jar <jar name> is the proper way to execute a jar.
The ant target is creating a manifest with a classpath attribute. If you look at those paths you'll notice that they are relative to the current directory. When you execute java -jar from the command line are you in the...
G:/dev/myproj
...directory?
Related
I have some code that I revised.
When I try to just run Ant in the directory it fails with missing classes. I can specify the location to the existing classes by using the -lib option to ant. The compile then works fine, however dist ZIP file that is created appears to have missing libraries, as when I try to run it, I see errors relating to missing classes which are the classes that I specified with the -lib option, so this is probably due to the way I have used the -lib option.
How can I force the regular Ant command to include the additional classes specified with the -lib command?
You can write a target that will copy your lib directory/files in your zip file.
Let's say create a temp dir then copy your files then execute target for copying lib directory and then zip temp dir.
<target name="copyLib">
<copy todir="${temp.dir}">
<fileset dir="${lib.dir}">
<include name="*.jar" />
</fileset>
</copy>
</target>
Update paths and call this target into your create zip target.
Compiler task could look like this:
<javac srcdir="${base}/src"
destdir="${base}/classes"
classpath="${base}/lib">
</javac>
And the zip task could look like this:
<zip
destfile="${base}/dist.jar"
basedir="${base}/classes"
includes="..."
excludes="...">
</zip>
So sources are compiled in classes and zipped in a jar, but libraries used for compile are not included in the jar, they are runtime dependencies.
I would suggest that you declare your paths at the top of your ANT scripts as follows, using a fileset.
<path id="build.path">
<fileset dir="lib" includes="*.jar"/>
</path>
Less error prone compared to forcing users to specify the correct "-lib" parameter.
Finally the same fileset can then be used to include the same jars inside the zip file you're creating:
<zip destfile="${dist.dir}/mycode.zip">
..
..
<fileset dir="lib" includes="*.jar"/>
</zip>
I have an application built in Java, which, when a certain button is pressed within the application, another jframe should popup with a message. The ant file I made places the runnable jar into a folder within my Eclipse project. When the jar is built, and I run the jar in the folder it was born in, it runs fine. I can click the button that makes the popup show up and it does, indeed, show up.
The problem comes when I move the jar out and say, onto the desktop. Then running the jar starts the application, but pressing the button does nothing (no popup).
Now, I know I had issues including some image resources before, and had to use getResource() etc. I do not see why I would have to do anything like this since all of the "resources" are just .class files which are specified in the build path. I mean, all the app should be doing is creating a jframe...
EDIT: adding build.xml
EDIT: slimmed build.xml down -- I think the problem is in the building of the JAR.
<!--Creates the deployable jar file -->
<target name="jar" depends="compile">
<echo>"Making Deployable Jar..."</echo>
<jar destfile="${shipping.dir}/POSsystem.jar" basedir="${build.dir}">
<fileset dir="." includes="${imgs.dir}/**"/>
<fileset dir="." includes="db/**"/>
<manifest>
<attribute name="Built-By" value="${user.name}"/>
<attribute name="Main-Class" value="${main-class}" />
<attribute name = "SplashScreen-Image" value="${splash-screen}" />
</manifest>
</jar>
<echo>"Success Making Deployable Jar..."</echo>
</target>
EDIT 3: Added output from running via the command line.
C:\Users\Matt\Desktop>java -jar POSsystem.jar
LOG COULD NOT BE CREATED!
java.io.IOException: The system cannot find the path specified
at java.io.WinNTFileSystem.createFileExclusively(Native Method)
at java.io.File.createNewFile(Unknown Source)
at pos.log.GeneralLog.beginLog(Unknown Source)
at pos.main.POSsystem.main(Unknown Source)
This is the first error. The application should keep a log.txt, within a log folder, within the JAR. You can see in the build.xml (first thing posted) that I add the log folder to be built in to the JAR, which is fine, but the path in my log.java code will obviously give me problems since it's a hard-coded path. So my question here is: How do I include a path to the resource in a JAR file. I know that to include an image I would do something like: javax.swing.ImageIcon(getClass().getResource("/images/pos_header_icon.png"));
but I'm not sure how to access a file location...
The application should keep a log.txt within a log folder, within the JAR.
As noted here, it is possible to extract a file from a JAR, modify the file, and restore the archive; but it is not practical to alter the JAR from which currently loaded classes are running. THis would be a particular problem for an ongoing log. Instead, solicit a suitable path using JFileChooser and save it among your application's java.util.Preferences. Some platforms have recommended paths, for example.
I am stuck in a very common problem.
I am plugging my jar (which has many dependencies on third party vendor) into an application server lib directory. If I just copy my jar along with its dependencies into server lib then server classpath becomes to long and hence server is not able to work. Therefore I want to package this Jar with all its dependencies in a single jar so that server's classpath doesn't become too long. I found on various forums that there is a utility to do this i.e. OneJar. But this utility works on executable jar. In my case, my final jar will not be executable.
Also I tried ZIPFileSetGroup utility provided by ANT but that is causing security issues with Manifest file.
Can you please help me in resolving this issue?
Thanks!
If you use Maven to build, you can use the maven dependency plugin and use the copy-dependency task. It will copy all dependencies into your jar file when it creates it.
If you manually add the jars to your jar file, then you need to make sure your jar file has a Manifest.mf file in it and specify the main class and classpath inside of that.
Manifest-Version: 1.0
Main-Class: com.mypackage.MainClass
Class-Path: my.jar log4j.jar
Another option may be to build an .ear file, that is usually how you see enterprise apps or a .war file for web apps when they package specific jar files with them. It sounds like you are using a server, so one of those formats may be a better fit for you.
Using zipgroupfileset in the jar task in ANT is the easiest approach.
<jar destfile="MyApplication.jar" filesetmanifest="mergewithoutmain">
<zipgroupfileset dir="lib" includes="*.jar" />
<!-- other options -->
<manifest>
<attribute name="Main-Class" value="Main.MainClass" />
</manifest>
</jar>
Note the filesetmanifest flag set to mergewithoutmain merges everything but the Main section of the manifests.
Signed jars are causing the SecurityException which need to be handled manually. If any classes associated with signed jars verify the signature on the jar as a whole then those will fail at runtime. Digest signatures against a particular file will be added to the manifest without a problem. Since problem is your classpath getting too large you may not be able to bundle all the jars into a single jar but merge most of them making the CLASSPATH manageable.
There is also : http://code.google.com/p/jarjar/
Create target directory with all dependent jars. Next move 10 jars into a temp directory and keep moving the jars in batches of 10 and each time try to create the single jar from that group. When you get the security exception you can isolate which one is causing the problem. Try divide-and-conquer approach. If you have 300 jars then only have to do this 30 times.
When you say
child process picks up classpath from server/lib directory
is this a process that is under your control? If the parent process were to specify the classpath just as
server/lib/*
(i.e. a literal *) then the target java process will enumerate the jar files in the lib directory itself - they do not all need to be named on the classpath.
But if the parent process is explicitly enumerating server/lib/*.jar to build the -cp value then you could take advantage of the fact that the Class-Path in a JAR manifest takes effect even if a JAR is not "executable". You could use a stanza like this to create a manifest-only JAR file
<!-- location of your 300 dependency JAR files, file1.jar ... file300.jar -->
<property name="lib.dir" location="lib" />
<fileset id="dependencies" dir="${lib.dir}" includes="*.jar" />
<pathconvert property="manifest.classpath" dirsep="/" pathsep=" "
refid="dependencies">
<map from="${lib.dir}" to="myapp" />
</pathconvert>
<jar destfile="myapp-manifest.jar">
<manifest>
<attribute name="Class-Path" value="${manifest.classpath}" />
</manifest>
</jar>
This will produce a JAR file named myapp-manifest.jar whose manifest contains
Class-Path: myapp/file1.jar myapp/file2.jar ... myapp/file300.jar
You put this file into server/lib and the 300 dependencies into a new directory server/lib/myapp. Now the generated -cp will include just one file (myapp-manifest.jar) but the resulting java process will have all the 300 myapp JAR files available to it.
I'm trying to create a jar from my eclipse and in order to be able to use the external .jars, I'm using this manifest with multiple .jars in the classpath:
Manifest-Version: 1.0
Sealed: true
Main-Class: src.BatchTester
Class-Path: . P:/Tools/xstream/1.4.2/lib/kxml2-2.3.0.jar P:/Tools/xstream/1.4.2/lib/xstream-1.4.2.jar P:/Tools/StringTemplate/4.0.5/lib/antlr-3.3-complete.jar P:/Tools/StringTemplate/4.0.5/lib/ST-4.0.5.jar P:/Tools/Jdbc/lib/sqljdbc4.jar
Obviously if I don't put the libraries in the classpath the following error appears:
java.lang.NoClassDefFoundError: com/thoughtworks/xstream/XStream
But when I put them in the classpath the error changes to:
java.lang.NoClassDefFoundError: src/BatchTester
So it seemps that it can't found my main class. I've tryed with several possibilities in the classpath, like adding or removing . to the classpath, but can't make it work.
Any idea of how can I solve this???
Thanks for your time and effort,
PS: After creating the .jar the classpath in the manifest inside looks like:
Class-Path: . P:/Tools/xstream/1.4.2/lib/kxml2-2.3.0.jar P:/Tools/xstr
eam/1.4.2/lib/xstream-1.4.2.jar P:/Tools/StringTemplate/4.0.5/lib/ant
lr-3.3-complete.jar P:/Tools/StringTemplate/4.0.5/lib/ST-4.0.5.jar P:
/Tools/Jdbc/lib/sqljdbc4.jar
with new lines and spaces, but even after changing it to the "right" format, I got the same problems.
PS2: I know that with some plugins like Fat-Jar you can make it work, but I don't want to insert more data than needed in my .jar
Finally I've copied all the libs into the /lib folder and add them into the .jar with an ant target since seems to be OK with the IT guys (because it is a small application).
Here is the ant(in case is useful for someone):
<?xml version="1.0" encoding="UTF-8"?>
<project name="BatchTester" default="compile" basedir=".">
<property name="external" value="lib/external-libs.jar"/>
<target name="compile">
<javac srcdir="jav"
source="1.6"
/>
<echo>Creating jar File</echo>
<!--create a new .jar with all the external jars in /lib-->
<jar jarfile="${external}">
<zipgroupfileset dir="lib/">
<include name="**/*.jar"/>
</zipgroupfileset>
</jar>
<!--<sleep seconds="1"/>-->
<!--create .jar file-->
<jar jarfile="BatchTester.jar" index="true" filesetmanifest="mergewithoutmain">
<fileset dir=".">
<include name="**/jav/**/*.class"/>
<exclude name="**/jav/**/*.java"/>
</fileset>
<zipfileset src="${external}">
<exclude name="META-INF/*.SF"/>
</zipfileset>
<manifest>
<attribute name="Main-Class" value="jav.BatchTester"/>
</manifest>
</jar>
<!--delete previously created extern .jar-->
<delete file="${external}"/>
</target>
</project>
Sorry If my questions sounds obvious for you.
*Launch Command *
In order to exclude any doubt, didn't you tried to launch your jar with this kind of command ?
java -jar myJar.jar -cp ./lib
If you use classpath option, you probably didn't ;). Option --classpath (or -cp) and -jar can't be uses together.
Prefer the use of relative path too, like ./lib instead of P:/Tools/... But, anyway, that won't solve your problem.
*Package Location *
As brimborium said, what is you real package ? src sounds very strange. We suspect an error around this.
In your BatchTester class, what have you written for package directive ? Nothing (i.e default package which isnot recommanded ?)?
Does you class begin with (get rid off comments)
public class BatchTester {
In that case, for sure, src should not be mentionned.
Here an example of manifest which work for me.
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: jrRevy
Build-Jdk: 1.6.0_31
Main-Class: com.sopragroup.training.dojo1.MainSwingApp
Class-Path: dojo1-0.5.0-SNAPSHOT-lib/spring-core-3.1.1.RELEASE.jar doj
o1-0.5.0-SNAPSHOT-lib/spring-asm-3.1.1.RELEASE.jar [blablabla]
with the following execution structure
/
|
+ --dojo1-0.5.0-SNAPSHOT.jar
|
+ --dojo1-0.5.0-SNAPSHOT-lib/
|
+ --spring-core-3.1.1.RELEASE.jar
Obviously, I'm using maven for build my app, but the main idea is in.
The manifest doesn't allow absolute paths in the Class-Path: tag. You have two alternatives:
Use relative paths as you already mention in your own answer
Use absolute paths via file protocol. This has been answered elsewhere too and it works absolute versus relative path names in jar manifest
Class-Path: file:///P:/Tools/xstream/1.4.2/lib/kxml2-2.3.0.jar
In addition, you should not edit the manifest.mf manually without being aware of several limitations:
line maximum length must not exceed 72 characters, and after breaking one line you must insert an space in the first column.
There must be a carriage return after the last line otherwise, the file can't be parsed correctly
I am attempting to create a JAR based on two separate Java packages. I can compile and run within Eclipse, but cannot get the code to function from the command line. I have Ant and the JDK correctly configured for usage, as I have an almost working Ant build script. The only problem is that the resulting JAR throws a ClassNotFoundException when I attempt to execute it.
The archive contains all the .class files from both packages in the correct directory hierarchy. Regardless, the JAR will throw the above mentioned exception.
The idea is to run this script from the top level directory that contains both packages.
Here are the relevant lines from my build script:
<manifest file="MANIFEST.MF">
<attribute name="Built-By" value="XBigTK13X"/>
<attribute name="Main-Class" value="com.main.MainClass"/>
<attribute name="Class-Path" value="./com/main/ ./secondpackage/shapes/" />
</manifest>
<jar destfile="App.jar"
basedir="./bin"
includes="**/*.class"
manifest="MANIFEST.MF"
excludes="App.jar"
/>
The JAR was correct the whole time. This error was thrown because I was attempting to run the JAR with the following command after creating a JAR:
java MainClass
I now realize that I need to explicitly target the JAR by using the following command:
java -jar MainClass.jar
Look in the resulting JAR file to make sure that the two packages have the correct path from the root. Your Class-Path statement in the manifest may not match the structure of folders containing the .class files.
Verify it by opening the JAR with a zip util.