0

I want build a Maven project with dependencies outside the .jar, but every dependency must be in a separate directory as:

libs/${dependency.groupId}/${dependency.artifactId}/${dependency.version}

Just like this:

/build
  my.jar
  /libs
    /org.yaml
      /snakeyaml
        /1.17
          snakeyaml-1.17.jar
    /etc...

I know that there is a maven-dependency-plugin, but how to configure it like that? Or there is any other plugin that can do this?

GotoFinal
  • 3,585
  • 2
  • 18
  • 33
  • 1
    `my.jar` will not be an executable JAR since it won't contain itself the dependency classes. It sounds like you want to create an assembly, like a custom ZIP? – Tunaki Jul 02 '16 at 12:48
  • @Tunaki it don't need to contain dependency classes, in real project there will be launcher too, that will get all libraries and run that .jar with valid classpath. I will edit title. – GotoFinal Jul 02 '16 at 12:51
  • 1
    Ok but I guess you need to package those inside a final container, like a ZIP or a TAR? – Tunaki Jul 02 '16 at 12:54
  • @Tunaki no, normal directory tree with all dependencies. – GotoFinal Jul 02 '16 at 12:55
  • Just don't forget to distribute a copy of the licences and notifications too. Snakeyaml, for example, is ASL 2, and that has a requirement that you *must* include a copy of its licence in the distribution. – Software Engineer Jul 02 '16 at 12:58
  • 1
    How are you building your final released archive then? – Tunaki Jul 02 '16 at 13:09
  • @Tunaki This is all I need, in future I might want pack everything from `/build` (including launcher and .jar) to single .zip, but that will be probably done via separate goal or utility. – GotoFinal Jul 02 '16 at 13:12

1 Answers1

3

What you really want to do here is to create a custom archive for your project. For that, you want to use the maven-assembly-plugin.

There are multiple aspects to consider:

  • You want a base directory of build. This is set by the <baseDirectory> parameter.
  • You want to have all of the project's dependencies in a repo-like directory layour. For that, you can use a custom outputFileNameMapping for the dependencySet. This enables to use a set of properties; in this case we're interested in the group id, artifact id and version. We need to disable <useProjectArtifact>, otherwise it would also include the project main artifact.
  • For the main artifact, we simply use a <file> element, pointing to the main artifact of the project.

The assembly descriptor would look like:

<assembly
    xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
    <id>bin</id>
    <formats>
        <format>dir</format> <!-- to turn into final archive type -->
    </formats>
    <baseDirectory>build</baseDirectory>
    <files>
        <file>
            <source>${project.build.directory}/${project.build.finalName}.${project.packaging}</source>
        </file>
    </files>
    <dependencySets>
        <dependencySet>
            <outputDirectory>libs</outputDirectory>
            <outputFileNameMapping>${artifact.groupId}/${artifact.artifactId}/${artifact.version}/${artifact.artifactId}-${artifact.version}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
            <useProjectArtifact>false</useProjectArtifact>
        </dependencySet>
    </dependencySets>
</assembly>

Note that it uses a <format> of dir, meaning that it does not "package" the output structure inside an archive but leaves it as a directory structure. In the future, you'll be able to customize this assembly descriptor with your launcher scripts and make a final archive of it by changing this format to the one you'll want.

Finally, the configuration of the plugin itself will be

<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>2.6</version>
    <executions>
        <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
            <configuration>
                <appendAssemblyId>false</appendAssemblyId>
                <descriptors>
                    <descriptor>src/main/assembly/assembly.xml</descriptor> <!-- path to the above assembly descriptor -->
                </descriptors>
            </configuration>
        </execution>
    </executions>
</plugin>

With such a configuration, launching mvn clean install will output the wanted directory structure inside target/${finalName}.

Tunaki
  • 132,869
  • 46
  • 340
  • 423
  • I can't figure out how to use that in multi-module project with parent poms, I keep getting `Failed to create assembly: Error adding file to archive: B:\path\artifact-1.0.pom`, adding it to exception list seems to not change anything. – GotoFinal Jul 02 '16 at 14:07
  • ok, I think that I got this, but I needed to create additional project that will be executed last and use this plugin in it. So thanks ;) – GotoFinal Jul 02 '16 at 14:23
  • one lest question if you are still here, there is any way to move that `baseDirectory` outside `artifact/target` directory? – GotoFinal Jul 02 '16 at 14:38
  • 1
    @GotoFinal That is a different concern. Everything generated by Maven should be placed inside `target`, and you really don't want to do otherwise. Generally speaking, when you have a final artifact, "moving" it outside of `target` means, in the Maven lingo, deploying it, with the help of `maven-deploy-plugin`: it will push your artifact to configured remote repositories. In this particular case of a directory structure, you could potentially use the `maven-antrun-plugin` and have an Ant task to copy it somewhere (like [here](http://stackoverflow.com/a/694175/1743880)). – Tunaki Jul 02 '16 at 14:46