1
votes

I'm working on a multi module maven project structured as follows:

SQR
+ pom.xml
+ core
| + src
| + target
| | + dependency-jars
| pom.xml
+ connector
| + src
| pom.xml
+ xmlreader
| + src
| pom.xml
+ xmlwriter
| + src
| pom.xml

The SQR is the top level project, whereas the core, connector, xmlreader, xmlwriter are modules. Currently the core builds everything together into a executable jar with external jar libs. The core uses several dependencies i.e. log4j, commons. So far so good. The problem arises modules are using specific dependencies i.e. http-client, commons-io. They all get added into class-path but they don't get copied to the core/target/dependency-jars. Another drawback is that I have to extend the pom.xml of every module when using dependencies (e.g. copy-dependencies etc.).

Currently I have the following files:

SQR/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.sqr</groupId>
    <artifactId>SQR</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <name>SQR</name>
    <url>http://maven.apache.org</url>
    <modules>
        <module>core</module>
        <module>connector</module>
        <module>xmlwriter</module>
        <module>xmlreader</module>
    </modules>
</project>

core/pom.xml:

<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.sqr</groupId>
    <artifactId>SQR</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <artifactId>core</artifactId>
  <packaging>jar</packaging>
  <name>core</name>
  <url>http://maven.apache.org</url>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <dependencies>
    [...]
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <scope>compile</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
        [...]
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>2.5.1</version>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <includeGroupIds>com.sqr, org.apache.commons</includeGroupIds>
                        <outputDirectory>${project.build.directory}/dependency-jars/</outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
  </build>
</project>

Other module pom.xml files look similar to the one listed above. It feels like much overhead, extending each pom.xml file. Is there a best practice to solve this problem? Or is there a quick and clean fix for this problem?

tl;dr: I want a multi module project where all modules and their dependencies get build into seperate .jar files and linked together. As follows:

+ dependency-jars
| commons-lang3-3.3.2.jar (used by only xmlwriter)
| connector-1.0-SNAPSHOT.jar
| xmlreader-1.0-SNAPSHOT.jar
| xmlwriter-1.0-SNAPSHOT.jar
| log4j-1.2.17.jar (used by all modules)
core-1.0-SNAPSHOT.jar (being the main entry of the application)
3

3 Answers

3
votes

The solution to your problem seems to be a distribution.

The following solution will help you to build a distribution artifact:

  • boot/core.jar
  • libs/connector.jar
  • libs/xmlwriter.jar
  • libs/xmlreader.jar

Don't worry it's simpler as it sounds!

  1. create a new module called ditrib

  2. create an assembly file: distribution.xml in the directory: src/main/assembly.

The content should be closed to this one:

<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>distrib</id>

<formats>
    <format>jar</format>
</formats>

<includeBaseDirectory>false</includeBaseDirectory>

<dependencySets>
    <dependencySet>
        <outputDirectory>/boot</outputDirectory>
        <includes>
            <include>${project.groupId}:core</include>
        </includes>
    </dependencySet>
    <dependencySet>
        <outputDirectory>/libs</outputDirectory>
        <includes>
            <include>${project.groupId}:connector</include>
            <include>${project.groupId}:xmlwriter</include>
            <include>${project.groupId}:xmlreader</include>
            <include>*:commons-lang3</include>
            <include>*:log4j</include>
        </includes>
    </dependencySet>
</dependencySets>

</assembly>
  1. Inside your pom, to create the distribution then declare:

         <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
                <descriptors>
                    <descriptor>src/main/assembly/distrib.xml</descriptor>
                </descriptors>
                <finalName>${project.artifactId}-${project.version}</finalName>
                <appendAssemblyId>false</appendAssemblyId>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    

This will generate a jar named *-distrib.jar in your target folder after issuing: mvn package.

NB: generally distribution comes with a config/config.properties file that does the glue between what is in the boot dir and what is in the libs directory. Also the distribution cannot be fully fledged without a bin/run.{sh|bat} files.

I hope, I helped you! Cheers!

2
votes

If your goal is to include the connector, xmlreader, and xmlwriter jars, along with all of their dependencies, into the dependencies folder of the core module, then a common method is to list those three modules as compile dependencies in the core module pom.xml, just as you would if the core module were a web module dependent upon lower level modules, such as domain or common.

Those modules do not appear in the dependencies section of the core module pom.xml that was listed. Adding them may not provide 100% of the solution to your problem, as custom packaging is being performed, but should move you significantly closer to the goal.

Edit: Remove

<includeGroupIds>com.sqr, org.apache.commons</includeGroupIds>

, then all transitive dependencies should be copied for connector, xmlreader, xmlwriter.

0
votes

Take a look to the Shade Plugin of Maven, maybe it could be helpful.

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