Author: aramirez
Date: Mon Feb 6 17:55:43 2006
New Revision: 375444
URL: http://svn.apache.org/viewcvs?rev=375444&view=rev
Log:
-added intro to optional and excludes dependencies
Added:
maven/site/trunk/src/site/apt/guides/introduction/introduction-to-optional-and-excludes-dependencies.apt
Added:
maven/site/trunk/src/site/apt/guides/introduction/introduction-to-optional-and-excludes-dependencies.apt
URL:
http://svn.apache.org/viewcvs/maven/site/trunk/src/site/apt/guides/introduction/introduction-to-optional-and-excludes-dependencies.apt?rev=375444&view=auto
==============================================================================
---
maven/site/trunk/src/site/apt/guides/introduction/introduction-to-optional-and-excludes-dependencies.apt
(added)
+++
maven/site/trunk/src/site/apt/guides/introduction/introduction-to-optional-and-excludes-dependencies.apt
Mon Feb 6 17:55:43 2006
@@ -0,0 +1,307 @@
+ ------
+ Optional Dependencies and Dependency Exclusions
+ ------
+ Allan Ramirez
+ ------
+ 23 January 2006
+ ------
+
+~~ Copyright 2001-2005 The Apache Software Foundation.
+~~
+~~ Licensed under the Apache License, Version 2.0 (the "License");
+~~ you may not use this file except in compliance with the License.
+~~ You may obtain a copy of the License at
+~~
+~~ http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing, software
+~~ distributed under the License is distributed on an "AS IS" BASIS,
+~~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~~ See the License for the specific language governing permissions and
+~~ limitations under the License.
+
+Introduction
+
+ This section discusses the functionality of optional dependencies and
+ dependency exclusions. This will help users to understand what are they,
+ how to use them, how they work and when is the best way to use them.
+ It also explains why exclusions are made as per dependency basis not in
+ a POM level.
+
+* Optional Dependencies
+
+ Optional dependencies are used when it's not really possible
+ (for whatever reason) to split a project up into sub-modules.
+ The idea is that some of the dependencies are only used for certain features
+ in the project, and will not be needed if that feature isn't used. Ideally,
+ such a feature would be split into a sub-module that depended on the core
+ functionality project...this new subproject would have only non-optional
+ dependencies, since you'd need them all if you decided to use the
+ subproject's functionality.
+
+ However, since the project cannot be split up (again, for whatever reason),
+ these dependencies are declared optional. If a user wants to use
+ functionality related to an optional dependency, they will have to redeclare
+ that optional dependency in their own project. This is not the most clear
+ way to handle this situation, but then again both optional dependencies and
+ dependency exclusions are stop-gap solutions.
+
+** Why use optional dependencies?
+
+ It's not only important to declare optional dependencies in order to save
+ space/memory/etc. It's vital to control the list of actual dependencies a
+ person needs in order to use a project, since these jars may eventually make
+ it into a WAR, EAR, EJB, etc. Inclusion of the wrong jars may violate a
+ license agreement, cause classpath issues, etc.
+
+** How do I use the optional tag?
+
+ A dependency is declared as optional by simply setting the \<optional\> tag
+ to true in your dependency declaration. See the sample below:
+
++---+
+
+<project>
+ ...
+ <dependencies>
+ <!-- declare the dependency to be set as optional -->
+ <dependency>
+ <groupId>sample.ProjectA</groupId>
+ <artifactId>Project-A</artifactId>
+ <version>1.0</version>
+ <scope>compile</scope>
+ <optional>true</optional> <!-- value will be true or false only -->
+ </dependency>
+ </dependencies>
+</project>
+
++---+
+
+** How do optional dependencies work?
+
++---+
+
+Project-A -> Project-B
+
++---+
+
+ The diagram above says that Project-A depends on Project-B. When A
+ declares B as an optional dependency in its POM, this relationship remains
+ unchanged. Its just like a normal build where Project-B will be added in its
+ classpath.
+
++---+
+
+Project-X -> Project-A
+
++---+
+
+ But when another project(Project-X) declares Project-A as a dependency in
+ its POM, the optional dependency takes effect. You'll notice that
+ Project-B is not included in the classpath of Project-X; you will
+ need to declare it directly in your POM in order for B to be included
+ in X's classpath.
+
+** Example
+
+ Let us say that there is a project named <X2> that has similar functions
+ with <Hibernate> which supports many database drivers/dependencies such as
+ mysql, postgre, oracle etc. All of these dependencies are needed for X2
+ to build but not for your project, so it is very practical for X2 to
+ declare these dependencies as optional, so that whenever your project
+ declares X2 as a direct dependency in your POM, all the drivers supported
+ by the X2 will not be automatically included to your project's classpath
+ instead you'll have to declare it directly on what driver/dependency of the
+ database you are going to use.
+
+* Dependency Exclusions
+
+ Since maven 2.x resolves dependencies transitively, it is possible
+ for unwanted dependencies to be included in your project's classpath.
+ Projects that you depend on may not have declared their set of dependencies
+ correctly, for example. In order to address this special situtation,
+ maven 2.x has incorporated the notion of explicit dependency exclusion.
+ Exclusions are set on a specific dependency in your POM, and are targeted
+ at a specific groupId and artifactId. When you build your project, that
+ artifact will not be added to your project's classpath <by way of the
+ dependency in which the exclusion was declared>.
+
+** How to use dependency exclusions
+
+ We add the \<exclusions\> tag under the \<dependency\> section of the pom.
+
++---+
+
+<project>
+ ...
+ <dependencies>
+ <dependency>
+ <groupId>sample.ProjectA</groupId>
+ <artifactId>Project-A</artifactId>
+ <version>1.0</version>
+ <scope>compile</scope>
+ <exclusions>
+ <exclusion> <!-- declare the exclusion here -->
+ <groupId>sample.ProjectB</groupId>
+ <artifactId>Project-B</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
+</project>
+
++---+
+
+** How dependency exclusion works and when to use it <<( as a last resort! )>>
+
++---+
+
+Project-A
+ -> Project-B
+ -> Project-D <! -- This dependency should be excluded -->
+ -> Project-E
+ -> Project-F
+ -> Project C
+
++---+
+
+ The diagram shows that Project-A depends on both Project-B and C. Project-B
+ depends on Project-D. Project-D depends on both Project-E and F. By default,
+ Project A's classpath will include:
+
++---+
+B, C, D, E, F
++---+
+
+ What if we dont want project D and its dependencies to be added to
+ Project A's classpath because we know some of Project-D's dependencies
+ (maybe Project-E for example) was missing from the repository, and you
+ don't need/want the functionality in Project-B that depends on Project-D
+ anyway. In this case, Project-B's developers could provide a dependency on
+ Project-D that is \<optional\>true\</optional\>, like this:
+
++---+
+<dependency>
+ <groupId>sample.ProjectD</groupId>
+ <artifactId>ProjectD</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <optional>true</optional>
+</dependency>
++---+
+
+ HOWEVER, they didn't. As a last resort, you still have the option to exclude
it
+ on your side, in Project-A, like this:
+
++---+
+
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>sample.ProjectA</groupId>
+ <artifactId>Project-A</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <packaging>jar</packaging>
+ ...
+ <dependencies>
+ <dependency>
+ <groupId>sample.ProjectB</groupId>
+ <artifactId>Project-B</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <exclusions>
+ <exclusion>
+ <groupId>sample.ProjectD</groupId> <!-- Exclude Project-D from
Project-B -->
+ <artifactId>Project-D</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
+</project>
+
++---+
+
+ If we deploy the Project-A to a repository, and Project-X declares a
+ normal dependency on Project-A, will Project-D be excluded from the
+ classpath still?
+
++---+
+
+Project-X -> Project-A
+
++---+
+
+ The answer is <<Yes>>. Project-A has declared that it doesn't need
+ Project-D to run, so it won't be brought in as a transitive dependency
+ of Project-A.
+
+ Now, consider that Project-X depends on Project-Y, as in the diagram below:
+
++---+
+
+Project-X -> Project-Y
+ -> Project-B
+ -> Project-D
+ ...
+
++---+
+
+ Project-Y also has a dependency on Project-B, and it does need the features
+ supported by Project-D. Therefore, it will NOT place an exclusion on
+ Project-D in its dependency list. It may also supply an additional
+ repository, from which we can resolve Project-E. In this case, it's
important
+ that Project-D <<is not>> excluded globally, since it is a legitimate
+ dependency of Project-Y.
+
+ As another scenario, what if the dependency we don't want is Project-E
+ instead of Project-D. How will we exclude it? See the diagram below:
+
++---+
+
+Project-A
+ -> Project-B
+ -> Project-D
+ -> Project-E <!-- Exclude this dependency -->
+ -> Project-F
+ -> Project C
+
++---+
+
+ Exclusions work on the entire dependency graph below the point where they
+ are declared. If you wanted to exclude Project-E instead of Project-D,
+ you'd simply change the exclusion to point at Project-E, but you wouldn't
+ move the exclusion down to Project-D...you cannot change Project-D's POM.
+ If you could, you would use optional dependencies instead of exclusions,
+ or split Project-D up into multiple subprojects, each with nothing but
+ normal dependencies.
+
++---+
+
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>sample.ProjectA</groupId>
+ <artifactId>Project-A</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <packaging>jar</packaging>
+ ...
+ <dependencies>
+ <dependency>
+ <groupId>sample.ProjectB</groupId>
+ <artifactId>Project-B</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <exclusions>
+ <exclusion>
+ <groupId>sample.ProjectE</groupId> <!-- Exclude Project-E from
Project-B -->
+ <artifactId>Project-E</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
+</project>
+
++---+
+
+** Why exclusions are made on a per-dependency basis, rather than at the POM
level
+
+ This is mainly done to be sure the dependency graph is predictable, and to
+ keep inheritance effects from excluding a dependency that should not be
+ excluded. If you get to the method of last resort and have to put in an
+ exclusion, you should be absolutely certain which of your dependencies is
+ bringing in that unwanted transitive dependency.