10

I'm having difficulty using the Maven Shade Plugin because I would like to have my shaded jar be installed to the same folder as the Parent pom (instead of the local src/target directory).

The layout: maven_project

guide/
   parent_pom.xml
projA/
   pom.xml
projB/
   pom.xml
   /target
      original-projB-0.0.3.jar
      projB-0.0.3.jar (shaded jar) 

I have to export the project and to make it easier for others to run the executable jar I want to relocate the shaded jar to the guide folder.

Unfortunately, I tried using

<outputDirectory>/home/name/Desktop/maven_project/guide/</outputDirectory>    

but this only moved the original-jar to the directory.

Question: Any ideas on how to move the shaded jar there instead (and even delete the original jar in the process)?

A_Di-Matteo
  • 26,902
  • 7
  • 94
  • 128
Max
  • 2,072
  • 5
  • 26
  • 42
  • 1
    did you configure the `outputDirectory` entry of the Jar Plugin or of the Shade Plugin? – A_Di-Matteo Feb 11 '16 at 20:39
  • 2
    It is [that `outputDirectory`](https://maven.apache.org/plugins/maven-shade-plugin/shade-mojo.html#outputDirectory) you should change. Side-note: a hard-coded value is fragile. Why not use `../guide`? – Tunaki Feb 11 '16 at 20:46
  • Yes, the output directory is within the shade plugin @A.DiMatteo – Max Feb 11 '16 at 21:15
  • 1
    @Max indeed I confirm, I was able to reproduce your behavior, gonna write an answer with two working solutions – A_Di-Matteo Feb 11 '16 at 21:32
  • I think the real problem here is that the Reactor or "parent-pom" must be packaged as a pom and not a jar. I'd prefer to be able to build the project and execute through only 1 directory ("/guide/"). – Max Feb 11 '16 at 21:40
  • @Max if I understand correctly: projA and projB are not modules and have guide as parent, parent has packaging jar? Why? Its output is just a pom, so it would be more correct to have packaging pom, as such you could also specify modules and have a proper reactor build – A_Di-Matteo Feb 11 '16 at 21:59

1 Answers1

13

The Maven Shade Plugin by default replaces the original jar generated by the build and creates a copy of it prefixed with original.

Replacement and relocation can be configured via the outputDirectory, outputFile and finalName configuration entries.

Applying the configuration below:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <executions>
                <execution>
                    <id>default-jar</id>
                    <phase />
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.4.3</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <finalName>${project.artifactId}-${project.version}-something</finalName>
                        <outputDirectory>../guide</outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

We are:

  • Firstly disable the generation of the default jar, as requested by your requirements and specified by this dedicated SO Q/A
  • Then configuring the Shade Plugin to relocate its output to the upper guide folder (via relative path, better approach as also suggested by @Tunaki)
  • Also configuring the finalName element in order to disable replacement (which also affects relocation, in the sense that also the (prefixed) original jar will be relocated). As per official documentation the finalName is

    The name of the shaded artifactId. If you like to change the name of the native artifact, you may use the <build><finalName> setting. If this is set to something different than <build><finalName>, no file replacement will be performed, even if shadedArtifactAttached is being used.

As such, Maven will generate only the shaded jar at the configured location.


Another approach, would be to use the outputFile configuration entry, which specifies:

The path to the output file for the shaded artifact. When this parameter is set, the created archive will neither replace the project's main artifact nor will it be attached. Hence, this parameter causes the parameters finalName, shadedArtifactAttached, shadedClassifierName and createDependencyReducedPom to be ignored when used.

Hence you could change the configuration above to:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <executions>
                <execution>
                    <id>default-jar</id>
                    <phase />
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.4.3</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <outputFile>../guide/${project.artifactId}-${project.version}-shaded.jar</outputFile>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

And have exactly the same behavior.


Side note: you are really changing the behavior of the build here. If somebody builds only a single module, from the module folder itself, he/she would not find the expected content on the target folder, which would be on the parent one instead (a bit of a surprise).


Update
Applying the configuration above and invoking only the Shade Plugin from the command line

mvn shade:shade

You will however have the following issue:

[INFO] --- maven-shade-plugin:2.4.3:shade (default-cli) @ test-addjar ---
[ERROR] The project main artifact does not exist. This could have the following
[ERROR] reasons:
[ERROR] - You have invoked the goal directly from the command line. This is not
[ERROR]   supported. Please add the goal to the default lifecycle via an
[ERROR]   <execution> element in your POM and use "mvn package" to have it run.
[ERROR] - You have bound the goal to a lifecycle phase before "package". Please
[ERROR]   remove this binding from your POM such that the goal will be run in
[ERROR]   the proper phase.
[ERROR] - You removed the configuration of the maven-jar-plugin that produces the main artifact.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
Community
  • 1
  • 1
A_Di-Matteo
  • 26,902
  • 7
  • 94
  • 128
  • 1
    Both work as they are intended except for the removal of the default jar. I get an error: maven-shade-plugin:2.4.3:shade (default) @ projB --- [ERROR] The project main artifact does not exist. This could have the following [ERROR] reasons: – Max Feb 11 '16 at 22:05
  • [ERROR] - You have invoked the goal directly from the command line. This is not [ERROR] supported. Please add the goal to the default lifecycle via an [ERROR] element in your POM and use "mvn package" to have it run. [ERROR] - You have bound the goal to a lifecycle phase before "package". Please [ERROR] remove this binding from your POM such that the goal will be run in [ERROR] the proper phase. [ERROR] - You removed the configuration of the maven-jar-plugin that produces the main artifact. – Max Feb 11 '16 at 22:07
  • @Max How are you invoking Maven? A simple `mvn clean package` should suffice. – Tunaki Feb 11 '16 at 22:10
  • 1
    yes @Tunaki I am invoking clean package from the guide directory – Max Feb 11 '16 at 22:11
  • @Max That error doesn't sound like any error that I know of... Is your build process checking for the presence of the main artifact? – Tunaki Feb 11 '16 at 22:14
  • @Max I got the same error while executing `mvn shade:shade`, but `mvn clean package` worked fine. The error is probably because while disabling the default jar creation as part of the default binding of the maven build, we also added a configuration of the shade plugin in an execution section. Moving out the configuration section so that it will apply to both executions and command line invocations didn't fix it though. So, are you sure you executed `mvn clean package` and not `mvn shade:shade`? – A_Di-Matteo Feb 11 '16 at 22:15
  • 2
    yes I use "mvn clean package" and no it didn't fix it, it's okay as a side product the original jar file is not much of a problem – Max Feb 11 '16 at 22:18
  • In my testing, whenever `finalName` is **not** the default `${project.artifactId}-${project.version}`, the fat jar is put into the specified `outputDirectory`. When it is the default, the original jar is placed there. I fail to see how this can be intended behavior... – Marv Jan 10 '21 at 12:36