NoClassDefFoundError при попытке запустить мою банку с java.exe -jar... что не так?

У меня есть приложение, которое я пытаюсь обернуть в банку для упрощения развертывания. Приложение компилируется и работает нормально (в окне Windows cmd) при запуске в виде набора классов, доступных из CLASSPATH. Но когда я разбиваю свои классы и пытаюсь запустить его с помощью java 1.6 в том же окне cmd, я начинаю получать исключения:

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

Самое смешное, что нарушение LogFactory похоже на commons-logging-1.1.jar, которое находится в указанном пути к классу. Файл jar (да, это действительно так):

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

Содержимое файла commons-logging-1.1.jar:

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 имеет класс LogFactory. И, наконец, содержимое манифеста jar:

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

Это меня насторожило и всех коллег, которых я прослушивал больше дня. Чтобы отбросить ответы, на данный момент, по крайней мере, сторонние решения для этого, вероятно, из-за лицензионных ограничений и политики компании (например: инструменты для создания exe или упаковки банок). Конечная цель - создать банку, которая может быть скопирована из моего окна разработки Windows на сервер Linux (с любыми зависимыми баночками) и используется для заполнения базы данных (так что пути к классам могут отличаться от среды разработки и развертывания). Любые подсказки к этой тайне будут очень благодарны!

Ответ 1

Параметр -jar взаимно исключает -classpath. См. Старое описание здесь

-jar

Выполнить программу, инкапсулированную в JAR файл. Первый аргумент - это имя файла JAR вместо имени класса запуска. Для того, чтобы этот параметр работал, манифест JAR файла должен содержать строку вида Main-Class: classname. Здесь classname идентифицирует класс, имеющий открытый static static void main (String [] args) метод, который служит отправной точкой вашего приложения.

Информацию о работе с файлами Jar и манифестами Jar файла см. в справочной странице инструмента Jar и в Jar trail учебника Java.

Когда вы используете этот параметр, JAR файл является источником всех пользовательских классов, а другие пути пути пользовательского класса игнорируются.

Быстрый и грязный взломать - добавить свой путь к пути класса bootstrap:

-Xbootclasspath/а: путь

Укажите путь, разделенный двоеточиями, директив, архивов JAR и ZIP-архивов, чтобы добавить к пути класса начальной загрузки bootstrap.

Однако, поскольку @Dan правильно говорит, правильным решением является обеспечение того, чтобы ваш манифест JAR содержал путь к классам для всех JAR, которые ему понадобятся.

Ответ 2

Вы можете опустить параметр -jar и запустить файл jar следующим образом:

java -cp MyJar.jar;C:\externalJars\* mainpackage.MyMainClass

Ответ 3

Это проблема, которая возникает,

если JAR файл был загружен из "C:\java\apps\appli.jar", и ваш файл манифеста имеет ссылку на класс: reference "lib/other.jar", загрузчик классов будет выглядеть в "C:\java\apps\lib\" для "other.jar". Он не будет смотреть запись JAR файла "lib/other.jar".

Решение: -

  • Щелкните правой кнопкой мыши по проекту, выберите "Экспорт".
  • Выберите папку Java и в ней выберите Runnable JAR File вместо JAR файла.
  • Выберите правильные параметры, а в разделе "Обработка библиотеки" выберите третий вариант, т.е. (скопируйте необходимые библиотеки в подпапку рядом с созданным JAR).

[ EDIT= третий вариант создает папку в дополнение к jar, вторая опция ( "Необходимые библиотеки пакетов в сгенерированный JAR" ) также может использоваться, поскольку у вас есть банка. ]

  1. Нажмите "Готово", и ваш JAR будет создан в указанной позиции вместе с папкой, содержащей JARS, указанную в файле манифеста.
  2. откройте терминал, укажите правильный путь к вашей банке и запустите его, используя эту команду java -jar abc.jar

    Теперь, что будет, загрузчик классов будет выглядеть в правильной папке для ссылочных JARS, так как теперь они присутствуют в той же папке, которая содержит ваше приложение JAR. Нет никакого исключения java.lang.NoClassDefFoundError..

Это сработало для меня... Надеюсь, это сработает и для вас!

Ответ 4

если вы используете внешние библиотеки в своей программе, и вы пытаетесь собрать все вместе в файл jar, это не так просто, из-за проблем с classpath и т.д.

Я бы предпочел использовать OneJar для этой проблемы.

Ответ 5

У меня была такая же проблема с моей банкой решение

  • Создайте файл MANIFEST.MF:

Манифест-версия: 1.0

Запечатан: true

Класс-путь:. lib/jarX1.jar lib/jarX2.jar lib/jarX3.jar

Основной класс: com.MainClass

  1. Щелкните правой кнопкой мыши по проекту, выберите "Экспорт".

выберите экспортировать все папки outpout для проверенного проекта

  1. выберите существующий манифест из рабочей области и выберите файл MANIFEST.MF

Это сработало для меня:)

Ответ 6

Я обнаружил, что когда я использую манифест, что для перечисления банок для пути к классам необходимо иметь пробел после перечисления каждой банки, например. "required_lib/sun/pop3.jar required_lib/sun/smtp.jar". Даже если он последний в списке.