I have two independent gwt based projects using pom aggregation , so four projects(or modules) in total. Tree looks like this .
Reactor1(just pom.xml)
|-- war1 (gwt related stuff)
`-- jar1 (Spring , hibernate etc)
and an other project but structure is exactly the same
Reactor2(just pom.xml)
|-- war2 (gwt related stuff)
`-- jar2 (Spring , hibernate etc)
While being independent they are part of same business project . One is say reporting project and other one is CMS .I want to centralize all the major dependencies say just for example GWT , Spring , Hibernate (as obviously the core ones) . So I am thinking of a tree like this .
Parent(GWT ,SPring,Hibernate)
|-- Reactor1 (just pom.xml)
| |-- war1 (gwt stuff from parent)
| `-- jar1 (Spring , hibernate etc from parent)
`-- Reactor2 (just pom.xml)
|-- war2 (gwt related stuff from parent)
`-- jar2 (Spring , hibernate etc from parent)
Can some one please advice me if I am on the right path . I am just thinking that war file this is also getting the dependencies that it did not need (like spring and hibernate etc) like wise jars are getting dependencies like gwt which they do not need . Does it matter or not ? or am I on a tangent here :) . Any advice would be really appreciated . (I know my formatting is looking horrible but I hope it makes sense)
Can some one please advice me if I am on the right path.
I think that you are definitely on the right path. Just create this Parent aggregating pom and declare the GWT, Spring, and Hibernate dependencies under the dependencyManagement element.
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.acme.business</groupId>
<artifactId>parent</artifactId>
<version>1.0.0</version>
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.5.5-Final</version>
</dependency>
...
<dependencies>
</dependencyManagement>
...
</project>
Then, in a child project, you can add a dependency on Hibernate Core using the following declaration:
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.acme.business</groupId>
<artifactId>reactor-1</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>jar1</artifactId>
...
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
</dependencies>
</project>
References
Introduction to the Dependency Mechanism
Dependency Management
Maven: The Definitive Guide
9.4.6. Dependency Management
Related
I'm using Ant to build a custom jar library, which then I'm using in Maven as dependency.
<dependency>
<groupId>test-lib</groupId>
<artifactId>test-lib</artifactId>
<version>1.0.0system</scope>
<systemPath>${basedir}/src/main/webapp/WEB-INF/lib/test-lib-1.0.0.jar</systemPath>
</dependency>
So, basically what I do now is:
1) run ant to build custom library (test-lib-1.0.0.jar)
2) run: mvn compile, to compile my project using custom library among others.
Is there an option for me to do all this (packaing custom jar & compiling project) from
Maven?
I've found maven run plugin, and here are my settings:
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.4
<executions>
<execution>
<phase>?????what to put here?????/phase>
<configuration>
<tasks>
<ant antfile="${basedir}/build.xml">
<target name="prepare-test-lib" />
</ant>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
But, when running: mvn compile it complains about missing artifact: test-lib-1.0.0.jar.
I've used compile, generate-resouces,... in <phase/> tag, but nothing seems to work.
Is it possible to solve this somehow using this plugin?
When using the Maven Antrun Plugin, Maven tries to resolve the dependencies to build ClassPaths for the AntRun invocation and you thus face a chicken and egg problem : you can't declare a dependency that will be created during AntRun execution that requires this dependency to run. This can't work.
My recommendation would be to mavenize your test-lib, to include it in your project build and to declare a regular dependency on it. In other words, what I mean is moving from Ant to Maven to build your test-lib and setting up a multi-modules project.
To illustrate things more "visually", something like this:
my-project
|-- my-module
| |-- src
| | `-- main
| | `-- java
| `-- pom.xml
|-- test-lib
| |-- src
| | `-- main
| | `-- java
| `-- pom.xml
`-- pom.xml
Where my-project/pom.xml is an aggregating pom with a <packaging>pom</packaging> and list the modules under a <modules> element:
<modules>
<module>my-module</module>
<module>test-lib</module>
</modules>
And where my-module/pom.xml declares a dependency on the test-lib artifact:
<dependency>
<groupId>your.group.id</groupId>
<artifactId>test-lib</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
I'm just giving a very high-level overview here, you need to read the documentation a bit for the details, I can't cover everything. Start with the first book from Sonatype (link below).
But that would be the right way to go (and you should just not (ab)use system scoped dependencies).
References
Maven: The Definitive Guide
We have a mother-ship project with several modules:
foo
+ foo-core
+ foo-resource
+ foo-util
+ foo-whatever
I want to allow developers to include the core, resource, and util modules as dependencies (excluding the -whatever module). I know that I can specify that they include each dependency, but it would be nice to allow for them to just specify something like
<artifactId>foo-sdk</artifactId>
And get everything that they need to develop a foo. This has the added advantage that it gives us the power to add (or remove) what goes into the sdk.
It would be best if foo-sdk was not just a jar with the other jars jammed in it. I'd rather it be a pom that simply points to the other artifacts.
I feel like I've seen this done before but can't find instructions to do it. I checked out Maven Assembly Plugin but it doesn't look like this is its intended use.
You can group dependencies in a project with a packaging of type pom. From the Maven book:
3.6.1. Grouping Dependencies
If you have a set of dependencies
which are logically grouped together.
You can create a project with pom
packaging that groups dependencies
together. For example, let's assume
that your application uses Hibernate,
a popular Object-Relational mapping
framework. Every project which uses
Hibernate might also have a dependency
on the Spring Framework and a MySQL
JDBC driver. Instead of having to
include these dependencies in every
project that uses Hibernate, Spring,
and MySQL you could create a special
POM that does nothing more than
declare a set of common dependencies.
You could create a project called
persistence-deps (short for
Persistence Dependencies), and have
every project that needs to do
persistence depend on this convenience
project:
Example 3.11. Consolidating Dependencies in a Single POM Project
<project>
<groupId>org.sonatype.mavenbook</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>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-hibernate3</artifactId>
<version>${springVersion}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysqlVersion}</version>
</dependency>
</dependencies>
<properties>
<mysqlVersion>(5.1,)</mysqlVersion>
<springVersion>(2.0.6,)</springVersion>
<hibernateVersion>3.2.5.ga</hibernateVersion>
<hibernateAnnotationsVersion>3.3.0.ga</hibernateAnnotationsVersion>
</properties>
</project>
If you create this project in a
directory named persistence-deps, all
you need to do is create this
pom.xml and run mvn install. Since
the packaging type is pom, this POM
is installed in your local repository.
You can now add this project as a
dependency and all of its dependencies
will be added as transitive
dependencies to your project. When you
declare a dependency on this
persistence-deps project, don't
forget to specify the dependency type
as pom.
Example 3.12. Declaring a Dependency on a POM
<project>
<description>This is a project requiring JDBC</description>
...
<dependencies>
...
<dependency>
<groupId>org.sonatype.mavenbook</groupId>
<artifactId>persistence-deps</artifactId>
<version>1.0</version>
<type>pom</type>
</dependency>
</dependencies>
</project>
If you later decide to switch to a
different JDBC driver (for example,
JTDS), just replace the dependencies
in the persistence-deps project to use
net.sourceforge.jtds:jtds instead of
mysql:mysql-java-connector and update
the version number. All projects
depending on persistence-deps will use
JTDS if they decide to update to the
newer version. Consolidating related
dependencies is a good way to cut down
on the length of pom.xml files that
start having to depend on a large
number of dependencies. If you need to
share a large number of dependencies
between projects, you could also just
establish parent-child relationships
between projects and refactor all
common dependencies to the parent
project, but the disadvantage of the
parent-child approach is that a
project can have only one parent.
Sometimes it makes more sense to group
similar dependencies together and
reference a pom dependency. This way,
your project can reference as many of
these consolidated dependency POMs as
it needs. Note
Maven uses the depth of a dependency
in the tree when resolving conflicts
using a nearest-wins approach. Using
the dependency grouping technique
above pushes those dependencies one
level down in the tree. Keep this in
mind when choosing between grouping in
a pom or using dependencyManagement
in a parent POM
Wouldn't this just be another sub-module foo-sdk with packaging pom and dependencies on foo-{core,resource,util}?
Is it possible to include several smaller pom files to create the parent pom file. (e.g. I would like to split the reporting, build sections into their own poms and include them in the parent pom) for managing them effectively
If you are using Maven 2, you can simply create several parent levels. The first pom.xml (pom1) will define the basic properties (such as repositories for example). The second pom.xml (pom2), which has pom1 as <parent>, will define the reporting information. And so on... Finally, the "real" pom.xml will inherit from the pom2 and will define its own properties.
You can create as many parent levels as you want (of course, it will be harder to maintain if you have 5 parent levels).
Note that Maven 3 talked about introducing the mixin concept, which will allow you to fragment your pom.xml into several files, but it looks like that is not happening now until maven 4
Not quite. You can't include reporting and build sections defined in smaller POMs, you can only inherit them from a parent POM.
If your POM is getting too large, it is possible (and recommended) to arrange your dependencies into logical groups. For example, for a GWT project, you could create a new POM for all of your persistence related to GWT as follows:
<project>
<groupId>org.yourcompany</groupId>
<artifactId>gwt-dependencies</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>com.google</groupId>
<artifactId>gwt-user</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>org.extjs</groupId>
<artifactId>gxt</artifactId>
<version>2.1.0</version>
</dependency>
<!-- etc -->
</dependencies>
</project>
These groups can then be included in your main POM.
More recently, the option of using Maven Tiles has become possible. The plugin will allow you to perform the mixin operations not provided by Maven 3. However, each mixin requires a released tile artefact.
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.
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