ChatGPT解决这个技术问题 Extra ChatGPT

Building a fat jar using maven

I have a code base which I want to distribute as jar. It also have dependency on external jars, which I want to bundle in the final jar.

I heard that this can be done using maven-assembly-plug-in, but I don't understand how. Could someone point me to some examples.

Right now, I'm using fat jar to bundle the final jar. I want to achieve the same thing using maven.


f
forkdbloke

Note: If you are a spring-boot application, read the end of answer

Add following plugin to your pom.xml The latest version can be found at

...
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>CHOOSE LATEST VERSION HERE</version>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>assemble-all</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
...

After configuring this plug-in, running mvn package will produce two jars: one containing just the project classes, and a second fat jar with all dependencies with the suffix "-jar-with-dependencies".

if you want correct classpath setup at runtime then also add following plugin

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <mainClass>fully.qualified.MainClass</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>

For spring boot application use just following plugin (choose appropriate version of it)

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <fork>true</fork>
        <mainClass>${start-class}</mainClass>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>repackage</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Current version of this plugin is now 2.4
This is now deprecated and the maven-shade-plugin should be used instead. See @phlogratos answer: stackoverflow.com/a/16222965/274350.
Can maven-assembly-plugin minimize size of fat jar?
@Richard Where do you see it is deprecated ? I couldn't find anything around here maven.apache.org/plugins/maven-assembly-plugin
@user3833308 "deprecated" may be the wrong word, but the documentation at maven.apache.org/plugins/maven-assembly-plugin says "If your project wants to package your artifact in an uber-jar, the assembly plugin provides only basic support. For more control, use the Maven Shade Plugin."
C
Community

You can use the maven-shade-plugin.

After configuring the shade plugin in your build the command mvn package will create one single jar with all dependencies merged into it.


This is now the correct way to do it. The maven-assembly-plugin documentation states: "If your project wants to package your artifact in an uber-jar, the assembly plugin provides only basic support. For more control, use the Maven Shade Plugin."
But how do I take that single .jar and use it for publishing?
I disagree that this is now the "correct" way to do it. if you just want basic behaviour then you can absolutely continue to use the assembly plugin. the shade plugin does advanced stuff like rewriting the bytecode to modify package names of dependencies, once you start getting into that with production code you are introducing additional risk which is not worth it if you don't have a good reason.
P
Patrick Favre

Maybe you want maven-shade-plugin, bundle dependencies, minimize unused code and hide external dependencies to avoid conflicts.

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.1.1</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <minimizeJar>true</minimizeJar>
                        <createDependencyReducedPom>true</createDependencyReducedPom>
                        <dependencyReducedPomLocation>
                            ${java.io.tmpdir}/dependency-reduced-pom.xml
                        </dependencyReducedPomLocation>
                        <relocations>
                            <relocation>
                                <pattern>com.acme.coyote</pattern>
                                <shadedPattern>hidden.coyote</shadedPattern>
                            </relocation>
                        </relocations>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

References:

http://maven.apache.org/plugins/maven-shade-plugin/plugin-info.html

http://maven.apache.org/plugins/maven-shade-plugin/shade-mojo.html


If one encounters Provider org.apache.xerces.jaxp.SAXParserFactoryImpl not found, just remove <minimizeJar>true</minimizeJar>.
If you get an "java.lang.SecurityException: Invalid signature file digest for Manifest main attributes" exception, then this addition to the above configuration section helps: stackoverflow.com/a/6743609/38368
F
Faisal Feroz

actually, adding the

<archive>
   <manifest>
    <addClasspath>true</addClasspath>
    <packageName>com.some.pkg</packageName>                     
    <mainClass>com.MainClass</mainClass>
  </manifest>
</archive>

declaration to maven-jar-plugin does not add the main class entry to the manifest file for me. I had to add it to the maven-assembly-plugin in order to get that in the manifest


m
matsev

You can use the onejar-maven-plugin for packaging. Basically, it assembles your project and its dependencies in as one jar, including not just your project jar file, but also all external dependencies as a "jar of jars", e.g.

<build>
    <plugins>
        <plugin>
            <groupId>com.jolira</groupId>
            <artifactId>onejar-maven-plugin</artifactId>
                <version>1.4.4</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>one-jar</goal>
                        </goals>
                    </execution>
                </executions>
        </plugin>
    </plugins>
</build>

Note 1: Configuration options is available at the project home page.

Note 2: For one reason or the other, the onejar-maven-plugin project is not published at Maven Central. However jolira.com tracks the original project and publishes it to with the groupId com.jolira.


Is it possible to choose dependencies that you want to package with? For example, if a.jar and b.jar are external jars and I want to package only a.jar into final jar, is it something possible/configurable?
I also see one-jar stuff got bundled in final jar too. This increased size of the final jar a lot. Is it possible to choose external jars that you intend to include in final jar? Here is the one-jar logs: pastebin.com/UwniQJ2X
I don't know if you can configure what is included or not. Basically, one-jar includes all dependencies that are specified by your project, including transitive dependencies, so yes, the final jar is likely to become big if you have a lot of dependencies. Some overhead will be added by one-jar, in order to get Java working with the "jar of jars" structure.
S
Stanislav

An alternative is to use the maven shade plugin to build an uber-jar.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version> Your Version Here </version>
    <configuration>
            <!-- put your configurations here -->
    </configuration>
    <executions>
            <execution>
                    <phase>package</phase>
                    <goals>
                            <goal>shade</goal>
                    </goals>
            </execution>
    </executions>
</plugin>