How do I put all required JAR files in a library folder inside the final JAR file with Maven?

假装没事ソ 提交于 2019-11-26 04:36:57

问题


I am using Maven in my standalone application, and I want to package all the dependencies in my JAR file inside a library folder, as mentioned in one of the answers here:

How can I create an executable JAR with dependencies using Maven?

I want my final JAR file to have a library folder that contains the dependencies as JAR files, not like what the maven-shade-plugin that puts the dependencies in the form of folders like the Maven hierarchy in the .m2 folder.

Well, actually the current configuration does what I want, but I am having a problem with loading the JAR files when running the application. I can\'t load the classes.

Here\'s my configuration:

<plugins>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
            <execution>
                <id>copy-dependencies</id>
                <phase>prepare-package</phase>
                <goals>
                    <goal>copy-dependencies</goal>
                </goals>
                <configuration>
                    <outputDirectory>${project.build.directory}/classes/lib</outputDirectory>
                    <overWriteReleases>false</overWriteReleases>
                    <overWriteSnapshots>false</overWriteSnapshots>
                    <overWriteIfNewer>true</overWriteIfNewer>
                </configuration>
            </execution>
        </executions>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
            <archive>
                <manifest>
                    <addClasspath>true</addClasspath>
                    <classpathPrefix>lib/</classpathPrefix>
                    <mainClass>com.myapp.MainClass</mainClass>
                </manifest>
            </archive>
        </configuration>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.6</source>
            <target>1.6</target>
        </configuration>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
            <execution>
                <id>install</id>
                <phase>install</phase>
                <goals>
                    <goal>sources</goal>
                </goals>
            </execution>
        </executions>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.5</version>
        <configuration>
            <encoding>UTF-8</encoding>
        </configuration>
    </plugin>

</plugins>

The project runs fine from Eclipse, and the JAR files are put in the library folder inside my final JAR file as I want, but when running the final JAR file from the target folder I always get ClassNotFoundException:

Exception in thread \"main\" java.lang.NoClassDefFoundError: org/springframework/context/ApplicationContext
Caused by: java.lang.ClassNotFoundException: org.springframework.context.ApplicationContext
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        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)
Could not find the main class: com.myapp.MainClass. Program will exit.

How can I fix this exception?


回答1:


The following is my solution. Test it if it works for you:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>${project.build.directory}/classes/lib</outputDirectory>
                <overWriteReleases>false</overWriteReleases>
                <overWriteSnapshots>false</overWriteSnapshots>
                <overWriteIfNewer>true</overWriteIfNewer>
            </configuration>
        </execution>
    </executions>
</plugin>

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <!-- <classpathPrefix>lib</classpathPrefix> -->
                <!-- <mainClass>test.org.Cliente</mainClass> -->
            </manifest>
            <manifestEntries>
                <Class-Path>lib/</Class-Path>
            </manifestEntries>
        </archive>
    </configuration>
</plugin>

The first plugin puts all dependencies in the target/classes/lib folder, and the second one includes the library folder in the final JAR file, and configures the Manifest.mf file.

But then you will need to add custom classloading code to load the JAR files.

Or, to avoid custom classloading, you can use "${project.build.directory}/lib, but in this case, you don't have dependencies inside the final JAR file, which defeats the purpose.

It's been two years since the question was asked. The problem of nested JAR files persists nevertheless. I hope it helps somebody.




回答2:


Updated:

<build> 
  <plugins> 
    <plugin> 
    <artifactId>maven-dependency-plugin</artifactId> 
    <executions> 
      <execution> 
        <phase>install</phase> 
          <goals> 
            <goal>copy-dependencies</goal> 
          </goals> 
          <configuration> 
             <outputDirectory>${project.build.directory}/lib</outputDirectory> 
          </configuration> 
        </execution> 
      </executions> 
    </plugin> 
  </plugins> 
</build> 



回答3:


The simplest and the most efficient way is to use an uber plugin like this:

          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <finalName>uber-${artifactId}-${version}</finalName>
            </configuration>
        </plugin>

You will have de-normalized all in one JAR file.




回答4:


The executable packer maven plugin can be used for exactly that purpose: creating standalone java applications containing all dependencies as JAR files in a specific folder.

Just add the following to your pom.xml inside the <build><plugins> section (be sure to replace the value of mainClass accordingly):

<plugin>
    <groupId>de.ntcomputer</groupId>
    <artifactId>executable-packer-maven-plugin</artifactId>
    <version>1.0.1</version>
    <configuration>
        <mainClass>com.example.MyMainClass</mainClass>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>pack-executable-jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

The built JAR file is located at target/<YourProjectAndVersion>-pkg.jar after you run mvn package. All of its compile-time and runtime dependencies will be included in the lib/ folder inside the JAR file.

Disclaimer: I am the author of the plugin.




回答5:


following this link:

How To: Eclipse Maven install build jar with dependencies

i found out that this is not workable solution because the class loader doesn't load jars from within jars, so i think that i will unpack the dependencies inside the jar.




回答6:


Here´s how I do it:

    <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.2</version>
            <configuration>
                <appendAssemblyId>false</appendAssemblyId>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
                <archive>
                    <manifest>
                        <mainClass>com.project.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>

And then I just run:

mvn assembly:assembly



回答7:


I found this answer to the question:

http://padcom13.blogspot.co.uk/2011/10/creating-standalone-applications-with.html

Not only do you get the dependent lib files in a lib folder, you also get a bin director with both a unix and a dos executable.

The executable ultimately calls java with a -cp argument that lists all of your dependent libs too.

The whole lot sits in an appasembly folder inside the target folder. Epic.

============= Yes I know this is an old thread, but it's still coming high on search results so I thought it might help someone like me.




回答8:


This is clearly a classpath problem. Take into consideration that the classpath must change a bit when you run your program outside the IDE. This is because the IDE loads the other JARs relative to the root folder of your project, while in the case of the final JAR this is usually not true.

What I like to do in these situations is build the JAR manually. It takes me at most 5 minutes and it always solves the problem. I do not suggest you do this. Find a way to use Maven, that's its purpose.



来源:https://stackoverflow.com/questions/11758594/how-do-i-put-all-required-jar-files-in-a-library-folder-inside-the-final-jar-fil

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!