I have an application that I'm trying to wrap into a jar for easier deployment. The application compiles and runs fine (in a Windows cmd window) when run as a set of classes reachable from the CLASSPATH. But when I jar up my classes and try to run it with java 1.6 in the same cmd window, I start getting exceptions:
C:\dev\myapp\src\common\datagen>C:/apps/jdk1.6.0_07/bin/java.exe -classpath C:\myapp\libs\commons -logging-1.1.jar -server -jar DataGen.jar
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
at com.example.myapp.fomc.common.datagen.DataGenerationTest.<clinit>(Unknown Source)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory
at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:276)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
... 1 more
The funny thing is, the offending LogFactory seems to be in commons-logging-1.1.jar, which is in the class path specified. The jar file (yep, it's really there):
C:\dev\myapp\src\common\datagen>dir C:\myapp\libs\commons-logging-1.1.jar
Volume in drive C is Local Disk
Volume Serial Number is ECCD-A6A7
Directory of C:\myapp\libs
12/11/2007 11:46 AM 52,915 commons-logging-1.1.jar
1 File(s) 52,915 bytes
0 Dir(s) 10,956,947,456 bytes free
The contents of the commons-logging-1.1.jar file:
C:\dev\myapp\src\common\datagen>jar -tf C:\myapp\libs\commons-logging-1.1.jar
META-INF/
META-INF/MANIFEST.MF
org/
org/apache/
org/apache/commons/
org/apache/commons/logging/
org/apache/commons/logging/impl/
META-INF/LICENSE.txt
META-INF/NOTICE.txt
org/apache/commons/logging/Log.class
org/apache/commons/logging/LogConfigurationException.class
org/apache/commons/logging/LogFactory$1.class
org/apache/commons/logging/LogFactory$2.class
org/apache/commons/logging/LogFactory$3.class
org/apache/commons/logging/LogFactory$4.class
org/apache/commons/logging/LogFactory$5.class
org/apache/commons/logging/LogFactory.class
... (more classes in commons-logging-1.1 ...)
Yep, commons-logging has the LogFactory class. And finally, the contents of my jar's manifest:
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.6.5
Created-By: 10.0-b23 (Sun Microsystems Inc.)
Main-Class: com.example.myapp.fomc.common.datagen.DataGenerationTest
Class-Path: commons-logging-1.1.jar commons-lang.jar antlr.jar toplink
.jar GroboTestingJUnit-1.2.1-core.jar junit.jar
This has stumped me, and any coworkers I've bugged for more than a day now. Just to cull the answers, for now at least, third party solutions to this are probably out due to licensing restrictions and company policies (e.g.: tools for creating exe's or packaging up jars). The ultimate goal is to create a jar that can be copied from my development Windows box to a Linux server (with any dependent jars) and used to populate a database (so classpaths may wind up being different between development and deployment environments). Any clues to this mystery would be greatly appreciated!
The -jar
option is mutually exclusive of -classpath
. See an old description here
-jar
Execute a program encapsulated in a JAR file. The first argument is the name of a JAR file instead of a startup class name. In order for this option to work, the manifest of the JAR file must contain a line of the form Main-Class: classname. Here, classname identifies the class having the public static void main(String[] args) method that serves as your application's starting point.
See the Jar tool reference page and the Jar trail of the Java Tutorial for information about working with Jar files and Jar-file manifests.
When you use this option, the JAR file is the source of all user classes, and other user class path settings are ignored.
A quick and dirty hack is to append your classpath to the bootstrap classpath:
-Xbootclasspath/a:path
Specify a colon-separated path of directires, JAR archives, and ZIP archives to append to the default bootstrap class path.
However, as @Dan rightly says, the correct solution is to ensure your JARs Manifest contains the classpath for all JARs it will need.