Skip to content

Instantly share code, notes, and snippets.

@bhuvangu
Last active December 31, 2018 11:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bhuvangu/be842153aa0abfb7858904b9783af91e to your computer and use it in GitHub Desktop.
Save bhuvangu/be842153aa0abfb7858904b9783af91e to your computer and use it in GitHub Desktop.

Understanding MAVEN - The core

Purpose of the article:

The article is about introducing maven, so that people joining projects which involve maven can start to understand the pom.xml and maven concepts.

This article describes

  • What was the problem in the java world which led to the birth of maven
  • How maven try to solve it.
  • Project coordinates
  • Dependency
    •   Example on project coordinate and dependency
      
  • Hint of build life cycle and plugins
  • Aggregator projects and parent pom
  • Parent pom and dependency management
  • Build Life-cycle, phases and plugin/goals
  • Parent pom and plugin-management
  • Some other section of pom.xml
  • P.O.M - Bigger Picture
  • Miscellaneous

What was the problem in the java world which led to the birth of maven

So let say there is software develop BOB, happy living his life with his java project and few shell script to build it.

But after few months into the project BOB started to see few problems.

1 Since now his project depends on lots of third party jars, he has to keep track of these jar versions and also dependency jar dependencies as well.

For example:
BOB's project use classes from A.jar(version 1.3.2) and classes in A.jar in turn depends upon PAPA.jar(version 1.1.0).

alt text

What BOB use to do is he pulls all these jar in a single folder called /lib and in his build script he points javac to /lib.

BUT NOW,
the jar dependency hierarchy has gone bigger and he has to manually pull all the depended dependency jars with correct version.
BOB project now has lots of internal project dependencies as well.
BobGui.jar depends upon BobImpl.jar which in turn depends on BobApi.jar which in turn depends on log4j.jar.
BobGui.jar also has a direct dependency on log4j.jar.

BOB script to build the project has gone really complex.

The project has gone really big and the management decided to put more developer and QA's into it and BOB suddenly got hit with the following problems:

  • New developers come-in and try to understand the jar dependencies and complex build script and gets Brain Fucked just to understand the build process and complex dependency hierarchy.

  • New developer come with his own code format few uses tab, some use spaces, few dont put comments, few just put empty comments, few dont put spaces between ),{`` =,+

  • These new developers start with their own formats.

  • BOB need some means to transfer all of the dependency jar to new guys so that they can setup the dev environment.

    • (aahhaa) i can transfer them the jar using pen drive...
    • (ooohhoo) will you always transfer the jar if you update your dependencies.. and what about remote developers.
  • Now since project has some QA's, BOB need some mean to deploy the application as well, so that QA can test it.

  • Since project has gone bigger it need some way to generate documentation, reporting as well.

  • BOB need some means to do versioning for produced jars.

    • (aaahaa) i can write custom scripts to do it.
    • (ooohhoo) company pays you to write code in project not to write and maintenance custom build scripts.

These are the problem faces by BOB which led to the birth of MAVEN


Lets start from the Maven official website:

Apache Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project's build, reporting and documentation from a central piece of information."

Let decode the cryptic terms in the official statement:

  • Project Management - this is not the project manager who want to get every
    thing delivered yesterday. But a software developer maintaining the surrounding code, dependency for its project.

  • Project object model (POM) - This is the central piece of information require by maven for its functioning

  • Project's build, reporting and documentation - It confirms that maven is going to build our source code to class files and create documentations


Lets step back and see what problem does BOB have:

  1. No way to manage the jar dependencies and thier dependent jar.
  2. Complex build scripts which other developer cant understand.
  3. No set method to do versioning of the jars
  4. No set method to deploy QA build
  5. No set method to setup a dev environment.
  6. No set method to keep check on code quality.
  7. No set method to run the unit tests.

###Now let see how Maven solves this problems: Maven guys come up with a strategy/plan/philosophy to solve above problem.

Maven philosophy:

"Convention over Configuration"

Maven guys said we will provide BOB the default templates on how he is going to structure its code in terms of files and folders and also BOB need to maintain a xml file called POM file.

If BOB follow the above two requirement then maven can take care of all other stuff i.e dependency resolution, build, deploying, generating reports.

(Seems Magic right!!! )
Lets try to see how does maven do it:

If we see the first requirement i.e "default templates on how BOB is going to structure its code in terms of files and folders" this is requires so that maven know where to find what ("convention over configuration").

The other and important thing is the POM file.
POM (project Object Model)...
What the heck that means....!!!!???

Maven guys developed a strategy and to full fill this strategy they come up with the pom..
so lets try to understand that pom:
Let say if each project/jar can tell:

1. What will be my jar name. (xyz.jar)   
2. Where to find my jar.   
3. What is my current version.   
4. What are my dependency.  

then pragmatically it is possible to just define direct dependency for a project and pull all dependencies dependency.

All the aboce information is put into pom.xml for each project, first 3 are represented as:

  <groupId>a.b.c.d</groupId>                #Tells where to find this jar  
  <artifactId>my_first_jar</artifactId>     #Name of the jar    
  <version>1.1.1</version>                  #Version of the jar  
  

## these 3 things together are called as "project coordinates"

what are my dependency is represented as:

<dependency>
<groupId>com.visionael.vnd_project.nrm_codegen</groupId>   #where to find this dependency jar
<artifactId>annotations</artifactId>   #dependency jar name
<version>${project.version}</version>  #dependency jar version
</dependency>

So basically we are just defining the project coordinates of dependency jars

Now the question arises that how <groupId>a.b.c.d</groupId> tells maven where to find the jar.

The answer is:

/<SOME_ROOT_PATH>/a/b/c/d/1.1.1/my_first_jar-1.1.1.jar
|-----<groupId>----------|-ver-|-artifactId-|version.jar

and this SOME_ROOT_PATH is /.m2/repository/ folder

Now the ovious question is how does jar reach /.m2/repository/a/b/c/d/1.1.1/my_first_jar-1.1.1.jar location ???

To get the answer for that we need to step back and look at the maven philosophy again.

Maven guys thought, now that we have project coordinates for dependency, but the big question in front of them is where to get the actual jar based on project coordinates.

So they come up with a central repository called maven repository which every body can use. maven repository is just like a hosted file system, more like ftp.

Now maven get the jar from central repository and place it in .m2 folder.
If you are thinking about why there are two places a central repository and a .m2 folder ???

We can think .m2 folder like a cache for the central repository. so that once maven download our dependency jar from central repo, it does not have to download them again.

And importantly made this rule that

Every dependency will only be server from first .m2 and then from central repo.

i will write it again....

Every dependency will only be server from first .m2 and then from central repo.

i will try to explain this line again in a paragraph:
so when ever maven see a <dependency> tag in pom.xml first it check in .m2 folder to find the jar if not found then look at the central repository, if still not found throw an error.

Now that we understand Maven philosophy let get back to the question:

How does my jar reaches /.m2/repository/a/b/c/d/1.1.1/my_first_jar-1.1.1.jar location ?
The answer is Maven.
Maven is the one who places jar to .m2 location when you build and install a project.(we will see how to build and install a project)
NOTE: Dont get confused with the team "install" installing here means placing the jar in .m2 folder.


Lets Conclude what we have learned till now:

  • A project is identified by project coordinates

      <groupId>a.b.c.d</groupId>              #Tells where to find this jar  
      <artifactId>my_first_jar</artifactId>   #Name of the jar
      <version>1.1.1</version>                #Version of the jar  
    
  • Dependencies defined for a project is server from a .m2 folder, if not found in .m2 then from central repository.


Time to dive into some examples where we will use what we have learned:

Example 1:

This example will show as the use of project coordinate and introduce as to some sort of life cycle involved.

  • create a file name pom.xml in an empty directory.

  • Put the following xml into pom.xml.

      <project>
          <modelVersion>4.0.0</modelVersion>
          <groupId>my.first.maven.project</groupId>
          <artifactId>first</artifactId>
          <version>1.1.1</version>
      </project>
    
  • Navigate to this pom.xml containing directory and run mvn install

If it gets successful, maven will print some junk, i have added ##### comments explaining the junk.

			[INFO] Scanning for projects...
			[INFO]
			[INFO] ------------------------------------------------------------------------
			[INFO] Building first 1.1.1
			[INFO] ------------------------------------------------------------------------
##### Maven is building a porject with name equal "first" and version equal "1.1.1"
			[INFO]
			[INFO] --- maven-resources-plugin:2.4.3:resources (default-resources) @ first ---
##### Maven is running the resources command (This a way to handle the resource file)
##### and this resource command come from  maven-resources-plugin:2.4.3
			[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
			[INFO] skip non existing resourceDirectory D:\tmp\maven\first\src\main\resources
			[INFO]
			[INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ first ---
##### Maven is compiling the code and the plugin used for compiling come from maven-compiler-plugin:2.3.2
			[INFO] No sources to compile
			[INFO]
			[INFO] --- maven-resources-plugin:2.4.3:testResources (default-testResources) @ first ---
##### Maven is compiling the resources from for junit(test)
			[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
			[INFO] skip non existing resourceDirectory D:\tmp\maven\first\src\test\resources
			[INFO]
			[INFO] --- maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @ first ---
##### Maven is compiling the tests java file
			[INFO] No sources to compile
			[INFO]
			[INFO] --- maven-surefire-plugin:2.7.2:test (default-test) @ first ---
##### Maven is running the tests using a plugin  " maven-surefire-plugin:2.7.2:test "
			[INFO] No tests to run.
			[INFO] Surefire report directory: D:\tmp\maven\first\target\surefire-reports

			-------------------------------------------------------
			 T E S T S
			-------------------------------------------------------
			There are no tests to run.

			Results :

			Tests run: 0, Failures: 0, Errors: 0, Skipped: 0

			[INFO]
			[INFO] --- maven-jar-plugin:2.3.1:jar (default-jar) @ first ---
##### Maven is packaging the compiled classed to a jar using a plugin maven-jar-plugin:2.3.1:jar				
			[WARNING] JAR will be empty - no content was marked for inclusion!
			[INFO]
			[INFO] --- maven-install-plugin:2.3.1:install (default-install) @ first ---
##### Maven is installing the jar to central repository which in our case is .m2 folder				
			[INFO] Installing D:\tmp\maven\first\target\first-1.1.1.jar to C:\Users\bhuvan\.m2\repository\my\first\maven\project\fir
			st\1.1.1\first-1.1.1.jar
			[INFO] Installing D:\tmp\maven\first\pom.xml to C:\Users\bhuvan\.m2\repository\my\first\maven\project\first\1.1.1\first-
			1.1.1.pom
##### Now go check in m2\repository\my\first\maven\project\first\1.1.1 location you will find your jar
			[INFO] ------------------------------------------------------------------------
			[INFO] BUILD SUCCESS
			[INFO] ------------------------------------------------------------------------
			[INFO] Total time: 1.300s
			[INFO] Finished at: Wed Jun 18 18:37:08 IST 2014
			[INFO] Final Memory: 4M/7M
			[INFO] ------------------------------------------------------------------------

pretty cool right!!

Lets spend some more time to investigate the above example:

  • In the pom that we used there is tag <modelVersion>
    This is a tag which is used by maven internally to know what to expect in the pom.xml.
    It is kind on versioning of pom structure that maven do.

  • We just run "mvn install" and maven itself did

  • Resource handling for the project

  • Compiling the code

  • Resource handling for the test(junit)

  • Compiling the test java files

  • Run the tests

  • package classes into a jar

  • placed the jar in .m2

maven did it itself because maven follow a default build life cycle which involve these 7 steps(this step are configurable, we will see it later)

Try running "mvn compile" and see whats the difference.

  • Another thing to note is each phase in build life cycle is executed by a plugin:

      maven-compiler-plugin:2.3.2:compile
      maven-resources-plugin:2.4.3:testResources    
      maven-compiler-plugin:2.3.2:testCompile    
      maven-surefire-plugin:2.7.2:test    
      maven-jar-plugin:2.3.1:jar    
      maven-install-plugin:2.3.1:install   
    

So that means maven is a plugin based build tool in which for each task there is a plugin.

WE HAVE JUST GOT INTRODUCED TO MAVEN BUILD LIFE CYCLE AND ITS PLUGIN ARCHITECTURE.
we will talk about it more later.


Example 2:

Our next example demo about the dependency management and dependency resolution
remember the maven philosophy:

Every dependency will only be server from first .m2 and then from central repo.

  • Let extend our pom.xml from previous example,let add a dependency to our project.

     				<project>
     				  <modelVersion>4.0.0</modelVersion>
     				  <groupId>my.first.maven.project</groupId>
     				  <artifactId>first</artifactId>
     				  <version>1.1.1</version>
     <!--      Dependency section       -->
     				  <dependencies>
     					<dependency>
     					  <groupId>my.second.maven.project</groupId>
     					  <artifactId>second</artifactId>
     					  <version>1.1.1</version>
     					</dependency>    
     				 </dependencies>
     				</project>
    

Now out project "first" depends upon project "second" i.e
first project jar use classes from second project jar.

  • Let try mvn install now:
    you should get some thing like this (i have put comment with #####):

     				[INFO] Scanning for projects...
     				[INFO]
     				[INFO] ------------------------------------------------------------------------
     				[INFO] Building first 1.1.1
     				[INFO] ------------------------------------------------------------------------
     				[WARNING] The POM for my.second.maven.project:second:jar:1.1.1 is missing, no dependency information available
     ###### maven cant find 	" my.second.maven.project:second:jar:1.1.1 " , which we expected as we havnt defined second project...
     				[INFO] ------------------------------------------------------------------------
     				[INFO] BUILD FAILURE
     				[INFO] ------------------------------------------------------------------------
     				[INFO] Total time: 0.284s
     				[INFO] Finished at: Wed Jun 18 20:06:56 IST 2014
     				[INFO] Final Memory: 2M/4M
     				[INFO] ------------------------------------------------------------------------
     				[ERROR] Failed to execute goal on project first: Could not resolve dependencies for project my.first.maven.project:first
     				:jar:1.1.1: Failure to find my.second.maven.project:second:jar:1.1.1 in http://50.18.154.216:8091/nexus/content/groups/p
     				ublic was cached in the local repository, resolution will not be reattempted until the update interval of nexus has elap
     				sed or updates are forced -> [Help 1]
     				[ERROR]
     				[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
     				[ERROR] Re-run Maven using the -X switch to enable full debug logging.
     				[ERROR]
     				[ERROR] For more information about the errors and possible solutions, please read the following articles:
     				[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/DependencyResolutionException
    

Since we have not defined pom for second project it got failed.
So lets define pom.xml for "second" project in a folder name "second"

<!-- second project pom -->
					<project>
					  <modelVersion>4.0.0</modelVersion>
					  <groupId>my.second.maven.project</groupId>
					  <artifactId>second</artifactId>
					  <version>1.1.1</version>
					</project>

Ok Now we have defined pom for second project as well and we now expect first project to build fine, so lets try that

  • Navigate to first project pom.xml file location in terminal and run mvn install

It still fails for the same reason that is cant find second project jar.
Why did that happened we did defined the pom for second project... right ???
Isnt maven suppose to find the second project and build it.
From very start we are saying maven will find dependency using pom.
so what happened now ?

The answer to it is in MAVEN philosophy i.e

Every dependency will only be server from first .m2 and then from central repo.

So if we consider the above philosophy we can explain the failed build.
When maven tried to build the first project it search for the dependency jar(second project jar) in .m2 and it did not find it because maven has never build and installed the second project jar.

So for "first" project to build we nee to build second project.
so lets do it.

  • Navigate to second project pom.xml file location in terminal and run "mvn install"
    Once the build is successful you should see second project jar in .m2 folder

  • Now lets navigate back to first project pom.xml and run "mvn install"

Bingo!! it got successful...

We just learned how to define dependencies and how dependencies get resolved.


Aggregator projects and Parent pom

Let try to analysis the above example again-

  • So when we tried to build first project it got failed as it wasnt able to find the "second" project jar. So after building "second" project , we were able to build first project.

So that means if first project depends on second, third and in turn third project depends on fourth then to build first project i need to first figure out dependency hierarchy and then build them In our case we need to build project in this order:

          "fourth" --> "second" --> "third" --> "first"

Calm down guys to facilitate that Maven guys come up with a tag called <module> and aggregator projects.

So now for maven to automatically build are complete project we will put first, second, third, fourth into a single folder name all_modules. and create pom.xml in all_module folder.

all_moule project is refered as aggregator project.

Folder structure:

/
|all_module
|    |
|    |- pom.xml
|    |
|    |-first
|    |    |- pom.xml
|    |-second
|    |    |- pom.xml

all_module/pom.xml content:

						<project>
						  <modelVersion>4.0.0</modelVersion>
						  <groupId>my.maven.projects</groupId>
						  <artifactId>projects</artifactId>
						  <packaging>pom</packaging>       <!-- For aggregator project packaging type cannot be jar,war,ear it has to be pom  -->
						  <version>1.1.1</version>
							<modules>
								<module>first</module>           <!-- modules to build  -->
								<module>second</module>
							</modules>
						</project>
  • Now navigate to all_modules using terminal and run mvn install

the output should be:(i have marked comment in #####)

				[INFO] Scanning for projects...
				[INFO] ------------------------------------------------------------------------
				[INFO] Reactor Build Order:
				[INFO]
				[INFO] projects
				[INFO] second
				[INFO] first
				[INFO]
       #### Order in which maven is going to build our projects...
				[INFO] ------------------------------------------------------------------------
				[INFO] Building projects 1.1.1
				[INFO] ------------------------------------------------------------------------
				[INFO]
				[INFO] --- maven-install-plugin:2.3.1:install (default-install) @ projects ---
				[INFO] Installing D:\tmp\maven\pom.xml to C:\Users\bhuvan\.m2\repository\my\maven\projects\p
				.pom
				[INFO]
				[INFO] ------------------------------------------------------------------------
				[INFO] Building second 1.1.1
				[INFO] ------------------------------------------------------------------------
				[INFO]
				[INFO] --- maven-resources-plugin:2.4.3:resources (default-resources) @ second ---
				[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build i
				[INFO] skip non existing resourceDirectory D:\tmp\maven\second\src\main\resources
				[INFO]
				[INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ second ---
				[INFO] No sources to compile
				[INFO]
				[INFO] --- maven-resources-plugin:2.4.3:testResources (default-testResources) @ second ---
				[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build i
				[INFO] skip non existing resourceDirectory D:\tmp\maven\second\src\test\resources
				[INFO]
				[INFO] --- maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @ second ---
				[INFO] No sources to compile
				[INFO]
				[INFO] --- maven-surefire-plugin:2.7.2:test (default-test) @ second ---
				[INFO] No tests to run.
				[INFO] Surefire report directory: D:\tmp\maven\second\target\surefire-reports

				-------------------------------------------------------
				 T E S T S
				-------------------------------------------------------
				There are no tests to run.

				Results :

				Tests run: 0, Failures: 0, Errors: 0, Skipped: 0

				[INFO]
				[INFO] --- maven-jar-plugin:2.3.1:jar (default-jar) @ second ---
				[WARNING] JAR will be empty - no content was marked for inclusion!
				[INFO]
				[INFO] --- maven-install-plugin:2.3.1:install (default-install) @ second ---
				[INFO] Installing D:\tmp\maven\second\target\second-1.1.1.jar to C:\Users\bhuvan\.m2\reposit
				second\1.1.1\second-1.1.1.jar
				[INFO] Installing D:\tmp\maven\second\pom.xml to C:\Users\bhuvan\.m2\repository\my\second\ma
				ond-1.1.1.pom
				[INFO]
				[INFO] ------------------------------------------------------------------------
				[INFO] Building first 1.1.1
				[INFO] ------------------------------------------------------------------------
				[INFO]
				[INFO] --- maven-resources-plugin:2.4.3:resources (default-resources) @ first ---
				[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build i
				[INFO] skip non existing resourceDirectory D:\tmp\maven\first\src\main\resources
				[INFO]
				[INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ first ---
				[INFO] No sources to compile
				[INFO]
				[INFO] --- maven-resources-plugin:2.4.3:testResources (default-testResources) @ first ---
				[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build i
				[INFO] skip non existing resourceDirectory D:\tmp\maven\first\src\test\resources
				[INFO]
				[INFO] --- maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @ first ---
				[INFO] No sources to compile
				[INFO]
				[INFO] --- maven-surefire-plugin:2.7.2:test (default-test) @ first ---
				[INFO] No tests to run.
				[INFO] Surefire report directory: D:\tmp\maven\first\target\surefire-reports

				-------------------------------------------------------
				 T E S T S
				-------------------------------------------------------
				There are no tests to run.

				Results :

				Tests run: 0, Failures: 0, Errors: 0, Skipped: 0

				[INFO]
				[INFO] --- maven-jar-plugin:2.3.1:jar (default-jar) @ first ---
				[WARNING] JAR will be empty - no content was marked for inclusion!
				[INFO]
				[INFO] --- maven-install-plugin:2.3.1:install (default-install) @ first ---
				[INFO] Installing D:\tmp\maven\first\target\first-1.1.1.jar to C:\Users\bhuvan\.m2\repositor
				st\1.1.1\first-1.1.1.jar
				[INFO] Installing D:\tmp\maven\first\pom.xml to C:\Users\bhuvan\.m2\repository\my\first\mave
				1.1.1.pom
				[INFO] ------------------------------------------------------------------------
				[INFO] Reactor Summary:
				[INFO]
				[INFO] projects .......................................... SUCCESS [0.257s]
				[INFO] second ............................................ SUCCESS [0.883s]
				[INFO] first ............................................. SUCCESS [0.227s]
				[INFO] ------------------------------------------------------------------------
				[INFO] BUILD SUCCESS
				[INFO] ------------------------------------------------------------------------
				[INFO] Total time: 1.495s
				[INFO] Finished at: Wed Jun 18 22:36:48 IST 2014
				[INFO] Final Memory: 4M/8M
				[INFO] ------------------------------------------------------------------------
  • The junk has started to make sense .. right...if you have just skipped reading the output please go back and read it

So these show us how maven can build stuff for us.


Now let see some other benefit of parent pom:

Lets get introduced to parent pom.xml and not to aggregator pom

why we are getting introduced to parent pom and not the aggregator pom

The answer is because we have already talk about the aggregator pom in previous section
####### That means parent pom is different from aggregator pom. Ok enough for the crap, Lets try to understand what parent pom is:

Lets see what problem does parent pom solve:

let say there are 20 modules each having their own pom.xml and project coordinate with version as 1.1.1.
Now assume all these 20 modules depends on a third_party.jar. so all 20 modules will have dependency in their pom.xml, like:

				<dependency>
                  <groupId>some.third.party</groupId>
                  <artifactId>third_party</artifactId>
                  <version>10.1</version>
                </dependency>

Now let say third_party.jar guys made a new release 10.2 which contains all the new functionality and you want to use these new jar.
So to use this new jar you have to go though all 20 modules and change that 1 dependency project version.

Editing of all 20 modules can be avoided by using the concept of PARENT POM
Lets see how..

  • Lets take a previous example from aggregator project section.

  • Edit first and second project pom to include <parent> tag like this

      <!-- basically coordinates of all_modules  -->
      		  <parent>
      				<groupId>my.maven.projects</groupId>
      				<artifactId>projects</artifactId>
      				<version>1.1.1</version>
      		  </parent>
    

We have just told maven that the parent of first and second project is all_modules

  • Again edit first and second project pom to include dependency as

      		<dependencies>
      			<dependency>
                    <groupId>some.third.party</groupId>
                    <artifactId>third_party</artifactId>
               <!-- we intentionally did not mentioned version -->
                  </dependency>
      		</dependencies>
    
  • Edit pom.xml under all_modules and add <dependencyManagment> tag as

          <dependencyManagement>
      		<dependencies>
      			<dependency>
                    <groupId>some.third.party</groupId>
                    <artifactId>third_party</artifactId>
                    <version>1.1.1</version>
                  </dependency>
      		</dependencies>
          </dependencyManagement>
    

Let explain what we did above:
$ we added <parent> tag in first and second project pom.
$ we then added the dependency in first and second project but without the version.
$ After that we added the <dependencyManagement> tag in all_modules pom and added the dependency of first and second project along with version.

Now when maven try to build the first and second project, it looks at the dependencies
if version found then ok
else go the parent pom and find the version from dependencyManagement section

This is how we can manage the dependency jar version from a single place that is parent pom.

Another important point to note here is that children poms are kind of inheriting properties from parent pom.
<dependencyManagement> is one section from where children pom can inherit properties there are other sections as well.

Defining dependency version in parent pom solves one more big problem
lets see what problem we might face if we dont define dependency version in parent pom.
let say project first uses log4j-1.1.jar.
so you will be defining log4j project coordinate in dependency of project first project.
Now assume second project depends on some third party jar 3rd_party_1.1.jar and this 3rd_party jar depends on log4j-1.0.jar

first  --> log4j-1.1.jar                     ##log4j version 1.1
second --> 3rd_party.jar --> log4j-.1.0.jar  ##log4j version 1.0
  • But during runtime there can only be one jar version ..unless you are doing custom classloaders..

so that means you did development assuming you are using 1.1 , but during runtime you used 1.0.... A big problem right ?

Now lets see how defining dependency version in parent pom resolves it.

What maven guys said is you define the dependency version in parent pom then maven will forcefully use that version jar to fulfill the dependency(without version) defined in children pom.

So if we define our dependency version in parent pom then we will do development assuming we are using 1.1 and during run-time as well we will be using 1.1


Lets again Conclude what we have learned till now:

  • A project is identified by project coordinates
    <groupId>a.b.c.d</groupId>              #Tells where to find this jar  
    <artifactId>my_first_jar</artifactId>   #Name of the jar
    <version>1.1.1</version>                #Version of the jar  
  • Dependencies defined for a project is server from a .m2 folder, if not found in .m2 then from central repository.
  • Just got introduced to MAVEN BUILD LIFECYCLE
  • Concept of aggreate project which helps to build multi module projects
  • Concept of parent pom(inheritance) and its benefit is resolving dependency versions.

Build Life Cycle

As promised earlier that we will talk about Build LifeCycle .. so let see what the heck is Build LifeCycle.
let pick up from where we left:
In pur first example we just run mvn install and maven itself did

            Resource handling for the project
			Compiling the code
            Resource handling for the test(junit)			
			Compiling the test java files
    		Run the tests
			Package classes into a jar
			Placed the jar in .m2

Time to get back to maven philosophy:
It is obvious that while building a project the above mentioned step has to be performed.
But how to do that considering following things in mind:

  • Maven plugin architecture,
  • Keeping convention over configuration and stil keep enough room for build process to be customizable
  • Fit in pom

So to address this maven guys come up with a philosophy i.e:

  • A plugin a made up of set of Goals.
  • A build life-cycle is made up of phases.
  • Each phases has a set of default plugin goal attached to it and users are allow to attach more plugin goal to a particular phase.

Lets try to understand each point mentioned in this philosophy...

  • A Plugin a made up of set of Goals"
    So maven itself is just a frame work which itself does not know how to build stuff.
    Maven plugin are the units that knows how to do actual work and a single plugin can perform more then one activity called goals.
    For example:

  • compile plugin maven-compiler-plugin V 2.3.6 brings compile and "testCompile" goals.

  • compile goal knows how to build source code and testCompile knows how to build test source code.

  • A build life-cycle is made up of Phases
    Another thing that maven does is break up the build process into a list of phases and calling a phase will call all phases above it
    Thats why in our earlier examples when we called mvn install it called whole bunch of stuff.
    For example:

  • Lets take a example of clean buildLifeCyle i.e mvn clean

  • Clean build life cycle consist of 3 phases

     pre-clean  
     clean   
     post-clean   
    
  • Now if you call mvn post-clean,execution will be something like

    pre-clean --> clean --> post-clean

To see phases in different life-cycle phases please refer
http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html

  • Each phases has a set of default plugin goal attached to it and users are allow to attach more plugin goal to a particular phase.
    Now we know that there are plugin/goal which known how to do work and there are phases in a build life-cycle. But these two thing are not connected.

Maven guys said there are default plugin goal associated with which phase based on packaging type and give end user the liberty to attach plugin goal to different phases based on their project needs

So to give end user the liberty to attach plugin goal to different phases Maven introduces <build>, <plugin>

For example:
let say you want to run some ant script in clean phase to do that we will use maven-antrun-plugin plugin:

       <build>        <!-- we want to configure the build process --> 
	   ...
       <plugins>
       ...
         <plugin>     <!-- we want to use plugin to configure the build process -->
            <artifactId>maven-antrun-plugin</artifactId>  <!-- plugin we want to use -->
            <version>1.1</version>  <!-- plugin version we want to use -->
            <executions>
		     ...
               <execution>
                 <id>my-ant-script</id>
                 <goals>
                   <goal>run</goal>  <!-- which goal fro maven-antrun-plugin do we want to run -->
                 </goals>
                 <phase>clean</phase>	<!-- in which phase we want to run the above goal -->
                 <configuration>  <!-- configuration require by antrun plugin -->
                   <tasks>
                      <echo>****ECHO MY ME****by****attaching****antrun***plugin***run****goal****to****clean****phase**</echo>
                   </tasks>
                </configuration>
               </execution>
		      ...
            </executions>
         </plugin>
	  ...
      </plugins>
	  ...
      </build>

If we run the a pom with above section in it then output should be :

[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building first 1.1.1
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.4.1:clean (default-clean) @ first ---
[INFO] Deleting D:\tmp\maven\first\target
[INFO]
[INFO] --- maven-antrun-plugin:1.1:run (my-ant-script) @ first ---
[INFO] Executing tasks
 [echo] ****ECHO MY ME****by****attaching****antrun***plugin***run****goal****to****clean****phase**
[INFO] Executed tasks
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.508s
[INFO] Finished at: Sun Jun 22 21:47:53 IST 2014
[INFO] Final Memory: 2M/5M
[INFO] ------------------------------------------------------------------------

AWESOME*!!!*

Since now we are introduced to plugins, we can learn a new tag <pluginManagement>.
Let say 10 out of 20 modules require above custom goal to attach to clean phase, in that case instead of adding the complete stuff to all 10 pom.
we can add above plugin in <pluginManagement> section of parent pom.xml and in 10 module pom only following is required:

<plugins>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
  </plugin>
</plugins>

Here we can see how inheritance come into picture again.


Lets again Conclude what we have learned till now:

  • A project is identified by project coordinates
    <groupId>a.b.c.d</groupId>              #Tells where to find this jar  
    <artifactId>my_first_jar</artifactId>   #Name of the jar
    <version>1.1.1</version>                #Version of the jar  
  • Dependencies defined for a project is server from a .m2 folder, if not found in .m2 then from central repository.
  • Just got introduced to MAVEN BUILD LIFECYCLE
  • Concept of aggreate project which helps to build multi module projects
  • Concept of parent pom(inheritance) and its benefit is resolving dependency versions.
  • We learned about the maven build life-cycle, phases and plugins/goals.
  • Saw how to manage plugin using <pluginManagement>

###Some other section of pom.xml In our pom we can also put informations like:

  • License ---------------- tell about the license of the project.
  • Developer ------------- tell about the developer of the project.
  • Contributors ---------- tell about the contributors of the project.
  • Organization ---------- tell about the Organization of the project.
  • IssueManagement --- tell about the issueManagement for the project.
  • Mailing list ------------- tell about the mailing list

P.O.M - Bigger Picture

alt text
Image from internet

The picture represent different part/section of pom.xml
I have discussed few part of the section that i think are important and make the crux of the pom.xml and after knowing these section we can now make intutive guess about other section just by name.

So In this article we have discussed:

  • POM Relationships
  • Some part of build Settings
  • General project information

Miscellaneous

Lets be good citizen of xml world

In our examples above we skipped some part for the sake of readability :

<?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/maven-v4_0_0.xsd">
....
</project>

so let be good citizen of xml world in future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment