LINUX.ORG.RU

Идиотский вопрос про java и maven - как забороть java.lang.NoClassDefFoundError ?

 ,


0

1

Собственно, по запуску падает с :

$ java -jar botweb-1.0-SNAPSHOT.jar ../test/config.json
Exception in thread "main" java.lang.NoClassDefFoundError: org/dom4j/DocumentException
        at com.alex4321.botweb.Database.initialize(Database.java:11)
        at com.alex4321.botweb.Application.main(Application.java:23)
Caused by: java.lang.ClassNotFoundException: org.dom4j.DocumentException
        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)
        ... 2 more

Ну то есть в

Configuration configuration = new AnnotationConfiguration().configure();
(где AnnotationConfiguration - класс из Hibernate).

В pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.alex4321.botweb</groupId>
    <artifactId>botweb</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.7</version>
        </dependency>
        <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-stdlib</artifactId>
            <version>1.0.2-1</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-commons-annotations</artifactId>
            <version>3.0.0.ga</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-annotations</artifactId>
            <version>3.3.0.ga</version>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.3-1102-jdbc41</version>
        </dependency>
        <dependency>
            <groupId>javax.transaction</groupId>
            <artifactId>jta</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.12.4</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.alex4321.bot</groupId>
            <artifactId>bot</artifactId>
            <scope>system</scope>
            <version>1.0-SNAPSHOT</version>
            <systemPath>${basedir}/lib/bot-1.0-SNAPSHOT.jar</systemPath>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.0.2</version>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>com.alex4321.botweb.Application</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.0.1</version>
                <executions>
                    <execution>
                        <id>copy-resources</id>
                        <!-- here the phase you need -->
                        <phase>validate</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>lib/</directory>
                                    <filtering>true</filtering>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.10</version>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/</outputDirectory>
                            <overWriteReleases>false</overWriteReleases>
                            <overWriteSnapshots>false</overWriteSnapshots>
                            <overWriteIfNewer>true</overWriteIfNewer>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

mvn package, конечно, завершается успешно. Как я понимаю - класс org/dom4j/DocumentException должен валяться в dom4j-1.6.1.jar, который в результате выполнения вполне себе оказывается в target :

$ pwd
/c/Users/gauss.DESKTOP-L34SIKM/IdeaProjects/untitled/target

gauss@DESKTOP-L34SIKM MINGW64 ~/IdeaProjects/untitled/target
$ cd ..

gauss@DESKTOP-L34SIKM MINGW64 ~/IdeaProjects/untitled
$ mvn package
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.877 s
[INFO] Finished at: 2016-06-29T11:19:00+03:00
[INFO] Final Memory: 38M/719M
[INFO] ------------------------------------------------------------------------

gauss@DESKTOP-L34SIKM MINGW64 ~/IdeaProjects/untitled
$ cd target

gauss@DESKTOP-L34SIKM MINGW64 ~/IdeaProjects/untitled/target
$ ls doc4*.jar
ls: cannot access 'doc4*.jar': No such file or directory

gauss@DESKTOP-L34SIKM MINGW64 ~/IdeaProjects/untitled/target
$ ls dom4*.jar
dom4j-1.6.1.jar

Однако :

gauss@DESKTOP-L34SIKM MINGW64 ~/IdeaProjects/untitled/target
$ java -jar botweb-1.0-SNAPSHOT.jar ../test/config.json
Exception in thread "main" java.lang.NoClassDefFoundError: org/dom4j/DocumentException
        at com.alex4321.botweb.Database.initialize(Database.java:11)
        at com.alex4321.botweb.Application.main(Application.java:23)
Caused by: java.lang.ClassNotFoundException: org.dom4j.DocumentException
        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)
        ... 2 more

-cp и путь до папки с жарами?

Deleted ()

По ходу ты с путями для зависимостей перехимчил. У меня так:

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>2.6</version>
        <configuration>
            <archive>
                <manifest>
                    <addClasspath>true</addClasspath>
                    <classpathPrefix>dependency</classpathPrefix>
                    <main-class>org.example.foo.Main</main-class>
                </manifest>
            </archive>
        </configuration>
    </plugin>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>2.10</version>
        <executions>
            <execution>
                <id>copydeps</id>
                <phase>package</phase>
                <goals>
                    <goal>copy-dependencies</goal>
                </goals>
            </execution>
        </executions>
    </plugin>

FeyFre ★★★★ ()

Когда ты запускаешь программу через -jar, jvm смотрит в META-INF/MANIFEST.MF твоего jar-файла, вытаскивает оттуда имя Main-класса и Classpath-а и использует их для запуска твоего приложения.

Когда приложение имеет зависимости, есть 3 основных способа его запуска:

  1. Без использования -jar. Обычно пишут sh-скрипт, который конструирует classpath (например перебирая все файлы в каталоге lib) и запускает java -cp $cp my.Main
  2. С использованием -jar без внешних зависимостей. В этом случае все jar-файлы сливаются в 1 большой jar-файл (т.н. uber jar). Минус в том, что некоторые библиотеки могут тебя не понять. На мой взгляд так лучше не делать, хотя для простых случаев скорее всего всё будет работать.
  3. С использоанием -jar и прописыванием Classpath в манифесте. Естественно всё должно быть прописано как положено и запускаться как положено.

Моё имхо — лучше всего использовать первый вариант. Он самый простой для понимания, скрипт пишется на коленке за 2 минуты (или гуглится) и все проблемы решаются быстро и просто. Преимущества -jar только в том, что в винде можно запускать дабл-кликом, но всё равно так никто не делает, серьёзные программы так или иначе пишут скрипты или лаунчеры.

Чтобы решить твою проблему — распакуй твой jar-файл, который ты запускаешь (jar xf или unzip), исследуй сгенерированный мавеном MANIFEST.MF, думаю проблема будет понятна после этого.

Legioner ★★★★★ ()
Последнее исправление: Legioner (всего исправлений: 1)

Если у тебя долгоиграющее приложение, н-р телеграм-бот который целый день висит после запуска, советую погуглить как работает Spring Boot, и запускать через него. Запускаемую джарку он сам тебе скомпонует с помощью собственного мавен плагина.

Может вечером напишу пример, но сейчас сильно влом

stevejobs ★★★★☆ ()
Последнее исправление: stevejobs (всего исправлений: 1)
Ответ на: комментарий от Legioner

В принципе, временно выкрутился вторым. За первый вариант - спасибо, как-то не подумал про шелл.

alex4321 ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.