NoClassDefFoundError при попытке запустить мой jar с java.exe -jar ... что не так? - PullRequest
55 голосов
/ 30 октября 2008

У меня есть приложение, которое я пытаюсь обернуть в банку для облегчения развертывания. Приложение компилируется и работает нормально (в окне 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 ...)

Да, в общем журнале есть класс LogFactory. И, наконец, содержимое манифеста моей банки:

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-файлов или упаковки фляг). Конечная цель - создать jar-файл, который можно скопировать из моей коробки Windows для разработки на сервер Linux (с любыми зависимыми jar-файлами) и использовать для заполнения базы данных (поэтому пути к классам могут отличаться в разных средах разработки и развертывания). Любая подсказка к этой тайне будет принята с благодарностью!

Ответы [ 6 ]

56 голосов
/ 30 октября 2008

Опция -jar является взаимно исключающей из -classpath. Смотрите старое описание здесь

-jar

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

См. Справочную страницу инструмента Jar и след Jar Учебного руководства по Java для получения информации о работе с файлами Jar и манифестами Jar-файла.

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

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

-Xbootclasspath / а: путь

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

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

28 голосов
/ 12 января 2012

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

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

17 голосов
/ 05 сентября 2012

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

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

Решение: -

  1. Щелкните правой кнопкой мыши проект, выберите «Экспорт».
  2. Выберите папку Java и в ней выберите Runnable JAR File вместо файла JAR.
  3. Выберите правильные параметры и в разделе «Обработка библиотек» выберите третий вариант, т. Е. (Скопируйте необходимые библиотеки в подпапку рядом с сгенерированным JAR).

[ EDIT = 3-й вариант создает папку в дополнение к jar, 2-й вариант («Упаковать необходимые библиотеки в сгенерированный JAR») также можно использовать, если у вас есть jar. ]

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

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

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

4 голосов
/ 30 октября 2008

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

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

2 голосов
/ 19 ноября 2015

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

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

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

Запечатано: правда

Class-Path:. lib / jarX1.jar lib / jarX2.jar lib / jarX3.jar

Main-Class: com.MainClass

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

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

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

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

0 голосов
/ 13 января 2012

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

...