5

I have a project with a submodule a:jar which needs a different set of dependencies, depending for which platform it is compiled. The code is the same for all platforms. E.g. on Android the httpcomponents library is already bundled with the OS, whereas I have to include it for builds for J2SE environments. I also have another submodule, which assembles several submodules and their dependencies into an archive. How can I reliably configure the assembly submodule, to take all the submodules compiled for the respective platform, and their dependencies appropriate for that platform?

I tried using profiles to create a:jar:android and a:jar:j2se. However, declaring a dependency on one of these would result in strange dependencies in the assembly. I.e., the dependency:tree of the assembly project would sometimes include the dependencies on a:jar:j2se (doesn't matter whether I declared to use the a:jar:android or a:jar:j2se in the assembly), and sometimes the other. It changed (often) after I updated the jars of a in the local repository. Switching in the assembly project uses also profiles.

I could solve that by applying the same dependencies to the assembly project's profiles as are needed by the individual submodules profile. But as I have to repeat myself in the POMs, there is probably a more maven-y way to achieve that. As I am quite new to maven, I wonder what it is? I don't want to duplicate the code (that would even be more repeating as the code stays the same) and I don't like to duplicate parts of the POM as changing them due to version upgrades can get complicated.

Some concrete material: Dependencies from a:jar's POM:

  <dependencies>
    .....
    <dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpmime</artifactId>
      <version>4.0.1</version>
      <scope>compile</scope>
      <!-- Exclusion in the common part, they are provided in the profiles from different sources -->
      <exclusions>
        <exclusion>
          <groupId>org.apache.httpcomponents</groupId>
          <artifactId>httpclient</artifactId>
        </exclusion>
        ....
      </exclusions>
    </dependency>
  </dependencies>
  <profiles>
    <profile>
      <id>android</id>
      <dependencies>
        <dependency>
          <groupId>com.google.android</groupId>
          <artifactId>android</artifactId>
          <version>1.6_r2</version>
          <scope>provided</scope>
        </dependency>   
      </dependencies>
    </profile>
    <profile>
      <id>java</id>
      <dependencies>
        <dependency>
          <groupId>org.apache.httpcomponents</groupId>
          <artifactId>httpclient</artifactId>
          <version>4.0.1</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>commons-codec</groupId>
          <artifactId>commons-codec</artifactId>
          <version>1.3</version>
          <scope>compile</scope>
        </dependency>
      </dependencies>
    </profile>
  </profiles>

The assembly project (which uses the Maven Assembly Plugin) profiles:

  <profiles>
    <profile>
      <id>android</id>     
      <dependencies>
        <dependency>
          <groupId>a</groupId>
          <artifactId>a</artifactId>
          <version>${project.version}</version>
          <classifier>android</classifier>
          <type>jar</type>
        </dependency>
        <!-- Duplicate --> 
        <dependency>
          <groupId>com.google.android</groupId>
          <artifactId>android</artifactId>
          <version>1.6_r2</version>
          <scope>provided</scope>
        </dependency>   
        <!-- Duplicate --> 
      </dependencies>
    </profile>
    <profile>
      <id>java</id>
      <dependencies>
        <!-- Duplicate -->
        <dependency>
          <groupId>org.apache.httpcomponents</groupId>
          <artifactId>httpclient</artifactId>
          <version>4.0.1</version>
          <scope>compile</scope>
        </dependency>
        <dependency>
          <groupId>commons-codec</groupId>
          <artifactId>commons-codec</artifactId>
          <version>1.3</version>
          <scope>compile</scope>
        </dependency>
        <!-- /Duplicate --> 
        <dependency>
          <groupId>a</groupId>
          <artifactId>a</artifactId>
          <version>${project.version}</version>
          <classifier>java</classifier>
         <type>jar</type>
        </dependency>
      </dependencies>
    </profile>
  </profiles>

I'd like to get rid of the marked dependency declarations.

Community
  • 1
  • 1
Stephan
  • 7,360
  • 37
  • 46

2 Answers2

3

There are several solutions:

  1. These submodule's dependencies could be declared "provided", in this case in a project you include the dependency to the submodule along with explicit dependencies which a platform doesn't have.

  2. Use <exclusions> for unnecessary dependencies.

  3. Using (1) or (2) above create yet another "structural" submodules a-android:pom a-j2se:pom which just describe dependencies, and use these modules from your projects.

kan
  • 28,279
  • 7
  • 71
  • 101
  • So for (3), "a-jse:pom" would inherit from "a". In "a"'s pom I don't declare any (or only common) dependencies. In the assembly project I would depend on "a-jse:pom" -- is that correct? That sounds like a good way... – Stephan Oct 04 '11 at 16:18
  • Yes, right. I think you have to declare some of the dependencies in "a" because they could be necessary for compilation. That's why you have to do either (1) or (2). Also, don't be confused with word "assembly", it's nothing to do with "Maven Assembly Plugin". – kan Oct 04 '11 at 16:23
  • I updated the original posting to contain more concrete code. Right now I'm trying to figure out how "a" and "a-j2se" must inherit from each other correctly. – Stephan Oct 04 '11 at 16:39
  • 1
    So, in "a" you have to delete whole `` block, then use "a" as is in android projects (it will work, because the platform provides the jar), add "httpclient" and "codec" dependencies as provided too. And create "a-java" project which will include "a", "httpclient" and "codec". And you don't need the assembly plugin or profiles at all. – kan Oct 04 '11 at 16:49
1

You can add a maven profile to pom and activate each profile based on the OS. Profile activation does support such an options. Then in each OS-specific profile you can list optional dependencies. Here is an article on profiles -> http://maven.apache.org/guides/introduction/introduction-to-profiles.html

In your case it would be something like this:

<profiles>
  <profile>
    <activation>
      <os>
        <family>Windows</family>
      </os>
    </activation>
    <dependencies>
      ... specific dependencies for Windows
    </dependencies>
    <plugins>
      ... specific build plugins for Windows
    </plugins>
  </profile>
  <profile>
    <activation>
      <os>
        <family>unix</family>
      </os>
    </activation>
    <dependencies>
      ... specific dependencies for unix
    </dependencies>
    <plugins>
      ... specific build plugins for unix
    </plugins>
  </profile>
  <dependencies>
    ... Common dependencies
  <dependencies>
  <plugins>
    ... Common build plugins
  </plugins>
</profiles>
Alexander Pogrebnyak
  • 44,836
  • 10
  • 105
  • 121
  • 2
    OS-specific profile is not appropriate here. It depends on build-server OS, but not on target OS. Moreover, it's very possible that it will be necessary to build several projects for several target platforms simultaneously. – kan Oct 04 '11 at 16:17
  • @kan. You can always generate OS-specific artifacts (in fact you MUST do this if you provide different components for different OS'es). Also, when building release, you can activate profiles by name, so you can build all profiles required on your CI server, and only ones appropriate for your dev environment on your dev machine. – Alexander Pogrebnyak Oct 04 '11 at 16:25
  • If you would use different modules for different OS-es you could create a root pom.xml which will include all of them as `` and build everything at once. For profiles you have to invoke maven several times with different profiles activated. – kan Oct 04 '11 at 16:30
  • I am aware of profiles (I updated the initial post), but the assembly plugin is not using the correct dependencies on "a". – Stephan Oct 04 '11 at 16:41