I have maven multiple-module project.
A: parent.
B: child1.
C: child2.
B will be packaged to get jar file and then c will use this jar file to compile the code.
In B, if I run mvn package, it will create b.jar (stays in B/target/jars not in B/target -for another purpose).
In C, I need to use that b.jar to compile the code.
Now, from A, when I run: mvn package. First, I am successful to create b.jar file for B.
But when it come to C's compilation phase, it looks like C doesn't recognize b.jar in the classpath (the compilation gets errors because C's code can not import the class file from B).
My question is: How can I solve this problem?
---------- Below are the pom files
A: pom.xml
<groupId>AAA</groupId>
<artifactId>A</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>C</module>
<module>B</module>
</modules>
B: pom.xml
<groupId>AAA</groupId>
<artifactId>B</artifactId>
<packaging>jar</packaging>
<version>0.0.1-SNAPSHOT</version>
<parent>
<artifactId>A</artifactId>
<groupId>AAA</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
C: pom.xml
<parent>
<artifactId>A</artifactId>
<groupId>AAA</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>AAA</groupId>
<artifactId>C</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>AAA</groupId>
<artifactId>B</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
....
Try ${project.version}
e.g.
<dependency>
<groupId>AAA</groupId>
<artifactId>B</artifactId>
<version>${project.version}</version>
</dependency>
Looks like it should work to me. But you might try mvn install instead of mvn package.
My question is how I can solve this problem?
Dependency resolution is done through the local repository so the canonical way to "solve" the problem is to run install from A so that modules will get installed in the local repository.
Now, regarding the following comment
But if I go with install then c war file will also be installed. That one is not accepted in my current project".
Sure, I'm not on your project, I don't know all constraints and rules. But if you decide to use Maven, this is a totally ridiculous policy (seriously, WTF?) and using a system scoped dependency is certainly not a good solution (more troubles later guaranteed). If this policy is real, better not use Maven in that case.
i have a solution: using the dependency with the scope=system
in C pom.xml
<dependency>
<groupId>AAA</groupId>
<artifactId>B</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>system</scope>
<systemPath>${basedir}\..\B\target\jars\b.jar</systemPath>
</dependency>
and in A pom.xml, put module B on the top like this
<modules>
<module>B</module>
<module>C</module>
</modules>
Doing mvn install only places the artifact into the local .m2 repository of the machine you're running the command on. How can that not be acceptable? I agree with Pascal. If you building A, there should be no reason that a the war is placed there.
On the other hand, if you're using Maven 2.2.x, take a look at the maven reactor plugin? This should help the crazy unacceptable cannot install C.war into your local .m2 repository policy for the current project.
If you have moduleA on your machine say at D:\moduleA and inside moduleA you have created another module say moduleB at D:\moduleA\moduleB , for you to use moduleB inside moduleA you create a dependency in the pom.xml file of moduleA like so:
<project xmlns="http://maven.apache.org/POM/4.0.0" ...>
...
<groupId>net.passioncloud</groupId>
<artifactId>moduleA</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>net.passioncloud</groupId>
<artifactId>moduleB</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependencies>
...
To compile the project so you can use it, from the module folder (moduleB) do:
.\mvnw clean install
Here are what I did to solve it:
From intelij , create new module from existing source.
Change the version of dependency B in A.pom same as version of B in B.pom
Related
Given three POM files:
C depends on B.
B inherits from A.
I can build A and B
C fails to build because of its dependency on B.
The full source-code and build output is included below for your review.
Here is A's POM:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.foo</groupId>
<artifactId>A</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>A</name>
<repositories>
<repository>
<id>foo releases</id>
<name>libs-releases-local</name>
<layout>default</layout>
<url>http://foo.net/artifactory/libs-releases-local</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.eclipse.swt</groupId>
<artifactId>swt</artifactId>
<classifier>${swt.classifier}</classifier>
<version>3.6.1</version>
</dependency>
</dependencies>
<profiles>
<profile>
<id>windows-x86</id>
<properties>
<swt.classifier>win32-x86</swt.classifier>
</properties>
</profile>
</profiles>
</project>
Here is B's POM:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.foo</groupId>
<artifactId>A</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../A</relativePath>
</parent>
<artifactId>B</artifactId>
<packaging>jar</packaging>
<name>B</name>
<profiles>
<profile>
<id>windows-x86</id>
<properties>
<swt.classifier>win32-x86</swt.classifier>
</properties>
</profile>
</profiles>
</project>
Here is C's POM:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.foo</groupId>
<artifactId>C</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>C</name>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>B</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
Here is the build output from C:
------------------------------------------------------------------------
Building C
task-segment: [install]
------------------------------------------------------------------------
[compiler:compile]
Nothing to compile - all classes are up to date
Downloading: http://foo.net/artifactory/libs-releases-local/org/eclipse/swt/swt/3.6.1/swt-3.6.1-${swt.classifier}.jar
[WARNING] Unable to get resource 'org.eclipse.swt:swt:jar:${swt.classifier}:3.6.1' from repository foo releases (http://foo.net/artifactory/libs-releases-local): Error transferring file: foo.net
Downloading: http://repo1.maven.org/maven2/org/eclipse/swt/swt/3.6.1/swt-3.6.1-${swt.classifier}.jar
Unable to find resource 'org.eclipse.swt:swt:jar:${swt.classifier}:3.6.1' in repository central (http://repo1.maven.org/maven2)
------------------------------------------------------------------------
[ERROR]BUILD ERROR
------------------------------------------------------------------------
Failed to resolve artifact.
Missing:
----------
1) org.eclipse.swt:swt:jar:${swt.classifier}:3.6.1
I know this issue is related to https://issues.apache.org/jira/browse/MNG-3228 but I'm not sure how to fix it. Please help!
UPDATE:
Adding a classifier to B helped. Now C builds so long as the repository only contains B's jar file. If I upload B's POM file alongside the JAR in the repository, C fails with the aforementioned error (${swt.classifier} not defined). Any ideas?
In a comment you write, "I am expecting SWT's classifier to get resolved at B's build-time, not C's build-time", but that is wrong - you need the classifier at C's build time because C has a dependency on swt (transitive via A). That dependency is only fully-determined by a property, so you have to have a way of evaluating the property in C's pom.
A depends on swt-${classifier}
C depends on A
therefore C depends on swt-${classifier}
therefore C's pom must define the property. It can be defined by a profile (as in A), or manually at runtime (bad for reproducibility), but you can't build C without it.
It's as simple (and puzzling) as that.
If you're expecting the property to somehow get fully "resolved" along the way, and be already well-defined by the time you build C, you are not understanding how Maven treats those properties. It leaves them alone. There was an attempt to do some different stuff in Maven 2.1 (the classifier property expression would be transformed to its value when you installed A), but it was not successful, caused many surprising behaviours, it was reverted for 2.2, and in fact caused 2.1 to be quickly deprecated. For more details, and some hints as to how complicated the problem really is, see the link below.
https://cwiki.apache.org/confluence/display/MAVENOLD/Artifact-Coordinate+Expression+Transformation
Until the Maven developers decide otherwise, I think we will continue to have the behaviour that has been around since 2.0: "Expressions in artifact coordinates are ignored. Users have plenty of rope with which to hang themselves"
Once you get used to it, though, it's not confusing anymore. It's only when you're trying to second-guess Maven that you get surprised.
Maven is trying to find the artifact org.eclipse.swt:swt:3.6.1 but the coordinates aren't being resolved correctly. The error is saying that ${swt.classifier} isn't being recognized from a <properties/> block in your POM.xml. Since that value shows up in a <profile/> block, can you verify what Maven command you are running?
Try this: mvn dependency:resolve -P windows-x86
Also, verify that both the version of SWT and the Classifier are actually correct. The latest version I see on Maven Central is not 3.6.0, but 3.3.0-v3346
This isn't possible as of Maven 3.1.0. Here is the relevant feature request: https://issues.apache.org/jira/browse/MNG-1388
I know this issue is related to https://issues.apache.org/jira/browse/MNG-3228 but I'm not sure how to fix it.
I'm not sure there is a link with this issue, I don't see anything related to profile activation in the pom.xml shown above.
Actually, I'm not even sure to understand the expected result. From where is the classifier supposed to come? Maybe I'm missing some parts but I think you should install/deploy a qualified version of B (with a fully resolved POM) and have C depend on this qualified version.
How would I need to modify B's POM to deploy a qualified version? I am expecting SWT's classifier to get resolved at B's build-time, not C's build-time.
Yes but at C's build-time, C needs B and B's dependencies so the installed/deployed .pom of B has to be fully resolved. At least, that's how I think things can work.
But I must admit I'm not sure how to handle this case exactly and after reading issues like MNG-4140 or the Artifact-Coordinate Expression Transformation page, I'm totally confused.
I suggest to post this on the maven users list for the right way (and I'll follow the thread closely because I think I have some broken POMs using profiles, properties and dependencies to fix now, thanks :)
In our Maven project, we are trying the following directory structure (with about 80 projects total, only a few are shown so that you get the idea):
myappli (pom)
-- module1 (pom)
--|-- utils (pom)
--|-- ejb (pom)
--|--|-- myappli-module1-a-ejb (jar)
--|--|-- myappli-module1-b-ejb (jar)
--|-- war (pom)
--|-- applet (pom)
...
-- module6 (pom)
--|-- utils (pom)
--|-- ejb (pom)
--|--|-- myappli-module6-c-ejb (jar)
--|-- war (pom)
--|-- applet (pom)
Note: This is a flat structure for Maven, as all non-leaf projects have a packaging value of "pom". (cf BetterBuildsWithMaven book).
We define the dependency versions in "dependencyManagement", in the "myappli" pom. This works fine.
Our problem is with the reuse of the dependencies themselves.
For example, the ejb dependencies are common to all ejb projects (by design).
We don't want to cut'n-paste, and maintain all that with each change!
We were thinking to use some "import notion" for the ejb dependencies, and define our ejb dependencies once at the application level. Our unsuccessful attempts were:
The Maven "parent pom" notion would be fine, but it is already used by the modules, so it is not available for our requirement.
No import facility found in Maven (except for dependencyManagement)
XML entity definition is not recognized. We tried a pom like the following, and got the error
"Reason: Parse error reading POM. Reason: could not resolve entity named 'ejbDependencies'":
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE project [
<!ENTITY ejbDependencies SYSTEM "./ejbDependencies.txt">
]>
<project ...
...
&ejbDependencies;
...
Edited : I am trying the solution suggested by Robert, but something is wrong.
When I compile my ejb project, it doesn't find the dependencies themselves. I get an error when compiling (mvn compile), saying the javax.ejb package is missing.
Note: I did run "mvn install" on the dependencies project before.
This is my configuration :
<project ...>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.company</groupId>
<artifactId>myproj-maven</artifactId>
<version>3.1-SNAPSHOT</version>
</parent>
<groupId>com.company</groupId>
<artifactId>myproj-maven-ejb</artifactId>
<version>${myproj-version}</version>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>javax.ejb</groupId>
<artifactId>ejb</artifactId>
</dependency>
<dependency>
<groupId>ojdbc</groupId>
<artifactId>ojdbc</artifactId>
</dependency>
</dependencies>
</project>
---------------------------------
<project ...>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.company</groupId>
<artifactId>myproj-identite-ejb</artifactId>
<version>3.1-SNAPSHOT</version>
</parent>
<groupId>com.company</groupId>
<artifactId>myproj-identite-metier</artifactId>
<name>SNR IDENTITE METIER</name>
<version>2.0.1</version>
<packaging>ejb</packaging>
<dependencies>
<dependency>
<groupId>com.company</groupId>
<artifactId>myproj-maven-ejb</artifactId>
<version>${myproj-version}</version>
<type>pom</type>
</dependency>
</dependencies>
</project>
I don't know if it changes something, but we have a hierarchy that relates the two poms.
We have a strict Maven structure, where each directory declares all subdirectories as maven modules, and each subdirectory declares the parent as a maven parent.
And the common parent directory is part of this structure.
+---maven
| \---ejb
+---identite
| +---ejb
| | \---SNR_IDENTITE_METIER
Edited:
The answer given by reef seem correct. It is impossible to do with Maven, because our dependency are provided, and therefore not transitive :-(
We really have many problems with setup up Maven. So many little things just don't work. Today I found out that the site target cannot handle properties, that we are using for version numbers!
You can use pom dependencies to import dependencies into arbitrary projects.
A pom project can look similar to:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>persistence-deps</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>${hibernateVersion}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>${hibernateAnnotationsVersion}</version>
</dependency>
</dependencies>
</project>
And is imported as:
<dependency>
<groupId>com.example</groupId>
<artifactId>persistence-deps</artifactId>
<version>1.0</version>
<type>pom</type>
</dependency>
See Maven, the definitive guide - Grouping Dependencies for details.
Do your imported dependencies have a provided scope?
Indeed this scope is not transitive (see Maven Dependency Scopes).
This could be the reason of the non-replacement.
I have several sub module (say A, B + C) that each generate an assembly tar.gz and a module (X) that will bundle them all together by extracting the tarballs into the target directory.
Right now setting up my dependency on A, B + C using the classifier and type in module X POM and using an assembly file with dependencySets the module does not seem to be pulling the tarball from my local repo, rather rebuilding it.
This is causing issues because A, B + C each has it's own filters. When X rebuilds A it leaves it unfiltered. I want maven to just either get the A-distro.tar.gz from my repo or if not present rebuild A, put it in the repo then have X use this.
Here is the assembly.xml file I'm using. I couldn't get moduleSets to work when using the coordinates so went for this:
<assembly>
<id>distro</id>
<formats>
<format>dir</format>
<format>tar.gz</format>
</formats>
<baseDirectory>${project.version}</baseDirectory>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<useTransitiveFiltering>true</useTransitiveFiltering>
<useProjectArtifact>false</useProjectArtifact>
<unpack>false</unpack>
<outputDirectory>/lib</outputDirectory>
<excludes>
<exclude>*:tar.gz</exclude>
</excludes>
</dependencySet>
<dependencySet>
<useTransitiveFiltering>true</useTransitiveFiltering>
<useProjectArtifact>false</useProjectArtifact>
<unpack>true</unpack>
<outputDirectory>/</outputDirectory>
<includes>
<include>*:tar.gz</include>
</includes>
</dependencySet>
</dependencySets>
</assembly>
And POM for project X:
<project>
<parent>
<artifactId>parent_project</artifactId>
<groupId>org.myorg</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.myorg</groupId>
<artifactId>X</artifactId>
<packaging>pom</packaging>
<name>X</name>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.myorg</groupId>
<artifactId>A</artifactId>
<classifier>distro</classifier>
<type>tar.gz</type>
</dependency>
</dependencies>
</project>
(RS moved content from OP's answer)
ok thanks for replying.
I've created a test project using the principle you describe of having one module for assembly, one for aggregator:
./pom.xml
./bundle
./bundle/pom.xml
./bundle/src
./bundle/src/main
./bundle/src/main/assembly
./bundle/src/main/assembly/assembly-files.xml
./bundle/src/main/assembly/assembly.xml
./module1
./module1/pom.xml
./module1/src
./module1/src/main
./module1/src/main/assembly
./module1/src/main/assembly/assembly-files.xml
./module1/src/main/assembly/assembly.xml
./module1/src/main/conf
./module1/src/main/java
./module1/src/main/java/org
./module1/src/main/java/org/test
./module1/src/main/java/org/test/Test.java
./module2
./module2/pom.xml
./module2/src
./module2/src/main
./module2/src/main/java
./module2/src/main/java/org
./module2/src/main/java/org/test
./module2/src/main/java/org/test/Test.java
Module 1 produces an assembly file of the following coordinates:
<dependency>
<groupId>org.test</groupId>
<artifactId>module1</artifactId>
<version>1.0-SNAPSHOT</version>
<classifier>distro</classifier>
<type>tar.gz</type>
</dependency>
The following file is produced:
~/mvnrepos/org/test/module1/1.0-SNAPSHOT/module1-1.0-SNAPSHOT-distro.tar.gz
When building the bundle with the following assembly the tar.gz is pulled in and used:
<assembly>
<id>distro</id>
<formats>
<format>dir</format>
<format>tar.gz</format>
</formats>
<baseDirectory>${project.version}</baseDirectory>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<includes>
<include>org.test:module1:tar.gz</include>
</includes>
<useTransitiveFiltering>true</useTransitiveFiltering>
<useProjectArtifact>false</useProjectArtifact>
<unpack>true</unpack>
<unpackOptions>
<excludes>
<exclude>lib/</exclude>
</excludes>
</unpackOptions>
<outputDirectory>lib/</outputDirectory>
</dependencySet>
</dependencySets>
<!-- just includes conf and bin dirs -->
<componentDescriptors>
<componentDescriptor>src/main/assembly/assembly-files.xml</componentDescriptor>
</componentDescriptors>
</assembly>
However if I cleardown my repository and clean the project at the root so the tar.gz is removed completely, when I change into the bundle dir and mvn install it fails as maven cannot work out it needs to rebuild module 1 in the absence of the tar.gz in order to get it. Here is my bundle pom:
<project>
<parent>
<artifactId>test_parent</artifactId>
<groupId>org.test</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.test</groupId>
<artifactId>bundle</artifactId>
<packaging>pom</packaging>
<name>bundle</name>
<version>1.0-SNAPSHOT</version>
<url>http://maven.apache.org</url>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.test</groupId>
<artifactId>module1</artifactId>
</dependency>
<dependency>
<groupId>org.test</groupId>
<artifactId>module2</artifactId>
</dependency>
<dependency>
<groupId>org.test</groupId>
<artifactId>module1</artifactId>
<version>1.0-SNAPSHOT</version>
<classifier>distro</classifier>
<type>tar.gz</type>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
How can I get maven to realize that the assembly must be rebuilt by rebuilding module 1?
I'm trying to keep each assembly within a separate module so each module can be built and tested as a separate unit rather than having an aggregator which needs to be rebuilt in order to run any of the modules. Then if the a full run is required the bundle can be built by simply untarring each assembly tarball into a directory under bundle/target.
Perhaps the above is going against the grain - but this seems to be the thrust of the maven assembly chapter in the Sonotype book:
http://www.sonatype.com/books/maven-book/reference/assemblies-sect-assembling-via-depend.html
Unfortunately the examples zip provided by sonotype has nothing under chapter 12 :-(
Of course I could just break out into ant and use this but would like to implement purely in maven if at all possible.
btw maven-assembly-plugin version is 2.2-beta-2.
I'm not sure I understand your problem so let me try to rephrase it.
You have 4 projects, A, B, C and X. You have A, B, and C defined as sub-projects of X
When you build project X you want to include the tar.gz files for projects A, B and C.
The problem is that you want to build A only if required, and download it from the project
repository if it is already present?
Assuming I understand the problem correctly, I'm still not clear how you expect the children to be conditionally built. If X declares the others as modules Maven will always build them along with the parent. If X declares the others as dependencies they will only ever be treated as dependencies, so the build will fail unless the artifacts exist in the repository (i.e. you've already built them).
If you want to be able to exercise flexibility over the build, I'd recommend separating the responsibilities of assembly and aggregator into different projects.
The aggregator simply declares the projects as modules so you can conveniently build all the projects in one command.
The assembly project (your project X) declares dependencies on projects A, B and C. When you build project X it is required that the others have already been built, but if built in the aggregator, the reactor will have built them first. Whereas if you build it standalone, you know the others are up to date.
Some additional points on Maven usage that should clarify this approach.
The Maven repository is a record of all the artifacts you've developed. You don't need to clear the local repository between builds. It is intended to act as a repository of all the artifacts. So if you install project A, that is the version that will always be used (unless and until you rebuild project A).
If you do have to clear the local repository, you should deploy your artifacts to a remote repository (see the relevant section of the Nexus book for guidance on getting started) so they can be incorporated into your build for project X even if the local repository is cleared.
So the workflow for building the projects is:
Run mvn install on the aggregator project or the relevant project (A,B, or C).
Projects are installed to the local repository.
Don't clear the local repository!
Run mvn install on project X, Maven will retrieve the dependencies from the repository and package them into your assembly.
If you use mvn deploy, the same principles apply, but because the artifacts are in the remote repository you have freedom to clear the local repository.
To emphasise my earlier points:
There is no mechanism to conditionally build modules. They either build or they don't (however some steps of the build might be skipped if they are not needed, e.g. compilation might have already been done in a previous build)
There is no need to purge the local repository (and if you do, you should have the modules deployed to a remote repository so they can be retrieved).
ok I should have been more clear on why I was clearing down the local repo - I understand this is not a normal step as part of the build cycle.
I was clearing down my local repo to emulate what would happen if I tried a build for the very first time and nothing exists on a remote repo. This is because on checking out the parent + modules all the code I need is present.
Parent
\----module1 (includes assembly classifier)
|
\----module2
|
\----bundle
eg build with empty repo from parentbuilds module1, module2 then bundle. All works well in this order:
parent, module1, module2, bundle
however if I have an empty repos and cd to X then build maven cannot work out that it needs to build the parent which depends on module1 and module2, so if possible I'd like it to build in this order:
parent, module1, module2, bundle
I think this is not possible in maven as you say there is no mechanism for conditional module builds! I thought maven would support this as it has info on the parent and the parent has info on the children, but I think I was inferring too much.
Many thanks for your replies Rich. Getting there with maven but it is like pulling teeth, in large part due to the style of the sonotype manual.
ps editing of questions looses context. I didn't realise stackoverflow did this. usenet style had it right first time, write your own reply, include references to former replies if required, post at the bottom. Editing prior posts IMHO erases the flow of a conversation - for some issues the journey to the solution is as instructive as the destination! this last paragraph is 400 chars :-)
eg I could not put this comment in as recommended because it goes over the technical sound barrier of 600 characters.
I'm using both the assembly and jar plugins to deploy my application. I'm also using the jar plugin to help me generate the classpath in the manifest file using
<addClasspath>true</addClasspath>
While that seems to work, the problem comes when I try executing the jar (it has a proper main class specified) - it will fail to locate a library that's actually a transitive dependency. So my project A depends on project B, and project B depends on jar C. The assembly plugin will correctly zip up A, B, and C, but the jar plugin did not include C in the manifest, causing a ClassNotFoundException.
I don't see any options in maven-jar-plugin that lets me specify that transitive dependencies are required.
Am I doing it the right way? Anyone else managed to get transitive dependencies generated into the manifest? Maybe I'm doing something wrongly or out of order. Any help appreciated.
i tried to solve the mentioned problem. in my case it worked (maven-jar-plugin v2.2).
i've got a parent project called jarloading that has 3 childs:
main: with dependency to a
a: with dependency to b
b: with dependency to a
after calling
mvn package
publishing it using a deploy script containing
rm -r ~/Desktop/jarloading-bin
mkdir ~/Desktop/jarloading-bin
cp a/target/a-0.0.1-SNAPSHOT.jar ~/Desktop/jarloading-bin/
cp b/target/b-0.0.1-SNAPSHOT.jar ~/Desktop/jarloading-bin/
cp main/target/main-0.0.1-SNAPSHOT.jar ~/Desktop/jarloading-bin/
changing to directory
cd ~/Desktop/jarloading-bin
and running
java -jar main-0.0.1-SNAPSHOT.jar
it worked fine.
but actually the point is, how the classpath is listed in manifest file:
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: rschmid
Build-Jdk: 1.6.0_07
Main-Class: Main
Class-Path: a-0.0.1-SNAPSHOT.jar b-0.0.1-SNAPSHOT.jar
pom.xml of main project:
...
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<index>true</index>
<manifest>
<mainClass>Main</mainClass>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>ch.fiftynine.lab</groupId>
<artifactId>a</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
...
pom.xml of a project:
...
<dependencies>
<dependency>
<groupId>ch.fiftynine.lab</groupId>
<artifactId>b</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
...
pom.xml of b project contains nothing really special.
and attached source code and binaries:
source code
binaries
I couldn't get the maven-jar-plugin to work, I had to use the maven-assembly-plugin.
Examples:
Brian Fox's Blog (this is the one I followed)
Maven Assembly Plugin Usage Guide
similar example by Scott Leberknight
I kinda managed to resolve by... not actually resolving it. I checked closer and still don't know why some transitive dependencies aren't getting picked up - it seems to skip of them and they end up not getting generated into the MANIFEST.
I dug around a bit and played with the maven-dependency-plugin. Surprisingly, configuring <attach>true</attach> and tying it to the assembly:assembly phase solved the classpath issue.
We have a solution with numerous wars. Wars are similar in the sense they all use hibernate and spring. This means that we have a number of same jars inside each war. This is becoming a problem, because the size of the ear is starting to grow out of proportion.
I would like to use Maven to calculate dependencies and to place all jars common to multiple wars to the root of the EAR.
I tried organizing my project using j2ee archetype (maven-archetype-j2ee-simple), but all wars are still packaged with dependencies inside the WEB-INF/lib.
Is there a way to make Maven calculate common dependencies and place them to EAR, just as he is able to calculate all transitional dependencies when constructing a war or a jar?
As you've mentioned in a comment, it's maven's task to calculate every dependency. When you're creating an artifact, with every common dependency, then you'll also have to guess, which dependencies belong there.
It could also be possible, that you have to deploy one war, with it's dependencies on another machine without an ear, an when you set every war dependency to provided, then you're stuck again.
The only right way, to get skinny wars is from the examples:
http://maven.apache.org/plugins/maven-war-plugin/examples/skinny-wars.html
But, and now comes the interesting part, there is one big! shortcut (which completly takes away the mentioned pain), to tell maven, which dependencies your WARs have.
Go inside your EAR-Module an declare a second dependency on the WAR with type pom for every WAR dependency.
<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>
<parent>
<groupId>com.foo</groupId>
<artifactId>skinny</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>ear</artifactId>
<packaging>ear</packaging>
<dependencies>
<dependency>
<groupId>com.foo</groupId>
<artifactId>war</artifactId>
<version>0.0.1-SNAPSHOT</version>
<type>war</type>
</dependency>
<dependency>
<groupId>com.foo</groupId>
<artifactId>war</artifactId>
<version>0.0.1-SNAPSHOT</version>
<type>pom</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>2.8</version>
<configuration>
<skinnyWars>true</skinnyWars>
<defaultLibBundleDir>lib</defaultLibBundleDir>
<modules>
<webModule>
<groupId>com.foo</groupId>
<artifactId>war</artifactId>
</webModule>
</modules>
</configuration>
</plugin>
</plugins>
</build>
Now, every WAR will be packaged independently with it's own dependencies and the EAR will be packaged with skinny WARs and every dependency inside the lib folder
Update:
Keep in mind, that the ear/lib folder can't be used for every dependency jar in a strict Container like JBoss EAP 6. JSF Component libraries like tomahawk, primefaces, etc. have to reside in WEB-INF/lib folder.
A handy way to achieve this with the above described solution is to make an exclusion for the component library in the EARs pom.xml like this:
...
<dependencies>
<dependency>
<groupId>com.foo</groupId>
<artifactId>war</artifactId>
<version>0.0.1-SNAPSHOT</version>
<type>war</type>
</dependency>
<dependency>
<groupId>com.foo</groupId>
<artifactId>war</artifactId>
<version>0.0.1-SNAPSHOT</version>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<exclusion>
</exclusions>
</dependency>
</dependencies>
...
Now every dependency of the WAR will be placed in ear/lib except the component library which will be placed in WEB-INF/lib inside the WAR
Create a new artifact named commons-jars and package it as pom. It should depend on all the common jars you are using - Spring, Hibernate, Log4j, etc.
Then, in each on your wars add it as dependency with scope "provided" (and don't forget to set the type as pom). You will be able to see it in your classpath but they won't be packaged into the war. This way you can also have war specific dependencies packaged into it, which the solution from skinny wars does not provide.
You can set the dependancies scope to "provided". This means they will be provided by some other module and will not be included in the final jar or war.
Perhaps the assembly plugin can help you when packaging up the final EAR and place common jars there.
http://maven.apache.org/plugins/maven-war-plugin/examples/skinny-wars.html