Java - Build Tools (Maven, Gradle)

Created:2018-03-08  Last modified:2020-03-29 WFH @ COVID-19


  1. Introduction

    A Java project building tool has functions of compiling, testing and downloading the required 3rd party packages. Java project has three main alternate building tools, Ant, Maven and Gradle. Ant and Maven build project according to XML. Gradle use its own DSL based on Groovy or Koltin (* Groovy and Koltin are two programming languages), and still use Maven's central repo for downloading dependencies.

    When building a Java project, developer should give the project name, version, and its dependencies.

    Java project vs. .NET project

    A java project have the code and test code together. A .NET project makes them as separate projects but in a solution of Visual Studio. It means when releasing a java program, we may not release its test and don't need test dependencies, such as Junit. So for a java project, there are three different kinds of dependencies, runtime, test, and provide dependencies. Provided dependencies is the product environment will provide the dependencies, e.g. Java servlet, but we still need have the dependencies in our environment when developing.

  2. Maven

    How does maven work?

    All maven's functionalities are based on plug-ins. Maven itself is developed by Java. Each plug-in is a .jar file.

    Each plug-ins may have serveral goals. The goal is just a task. For example, the compiler plug-in has the goal of compiling application source; compiling test case; display help information. To invoke a goal, run mvn plug-in:goal -Doptional-arguments.

    For example, when running mvn compile, the mvn program will use the Java dynamic load class feature to load the compile .jar file. And then the compile plugin will compile the project.

    The dynamic loading class feature is supported by the plexus-classworld framework.

    Maven central repo.

    Maven project structure

        pom.xml
        src/
            main/
                java/
                    package
            test/
                java/
                    package
            [resources/]
        target/
            classes/
            maven-status/
            surefire-reports/
            test-classes/
    
    

    The main directory is stored the source code; The test directory is for testing the source code, such as using junit.

    resources is optional. It stores images and other resource files.

  3. POM (Project Object Model)

    The file contains information about how to build the project. Information includes dependent packages name and version, source directory location, output location

    Terms

    • SuperPOM: a pom that is inherited by all user-define pom. See the SuperPOM
    • Repository: the location of for getting the dependent java .jar and maven plugins. Local directory (.m2/reposity) and remote directory
    • Reporting:

    Inside the super pom, it defines

    1. the location of the central remote repository for package and maven plugins (where to download).
    2. Source code and output directory
    3. Reporting directory
    4. Core plugins and their version, e.g. maven-compiler-plugin

    User-defined minimal POM

    It needs to specify the project name, version. And its dependencies.

      <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>
    
        <groupId>com.maven.practice</groupId>
        <artifactId>maven-practice-01</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>
        <name>short-description-of-the-project</name>
        <description>description-of-the-project</description>
        <developers></developers>
        <license></license>
        <organization></organization>
    
        <--add dependency-->
        <dependencies>
            <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.8.9</version>
                <type></type>
                <scope>test/main where is the package used</scope>
                <optional>true/false???</optional>
                <exclusions>
                    <exclusion>
                        this project, maven-practice-01 depends on the aspectjweaver
                        suppose the aspectjweaver depends on the logger.
                        The by default, the maven-practice-01 will also import the logger.
    
                    </exclusion>
                </exclusions>
            </dependency>
    
        </dependencies>
        <build>
            <plugins>
            </plugins>
        </build>
        <parent></parent>
        <module></module>
      </project>
    
  4. Plug-ins (commands)

    Plug-ins are just .jar packages. Each jar package achieves a collection of goals, which are simple tasks, such as compile, run test cases. Most of the plug-ins have a common goal, help, which prints the help message.

    A goal may allow the user to input arguments by using the format -Darg_name=arg_value.

    To invoke a goal, run mvn plugin:goal [-Darg_name=arg_vale]

    Plug-ins

    1. archetype

      Automatically generate a skeleton project structure, i.e. the directories and pom.xml, based on a template or a existing project.

      1. Generate from a template

        $ mvn archetype:generate
        # It would ask groupId, artifactId, version and package
        # groupId = package name e.g. com.maven.practice
        # artifactId = module-name (It will be the name of the top level directory) e.g. maven-practice-basic
        # version = version number e.g. 0.0.1-SNAPSHOT
        # package = package
        
        
    2. compiler

      Compile the source.

      Changing jre version: go to setting, add the profile tag.

      1. Compile the source code

        $ mvn compiler:compile
        
        
    3. jar

      Generate the jar package. It has 3 goals: help, jar, test-jar, and 2 deprecated goals: sign, sign-verify

      1. Generate the jar package of the source code, output is in the target directory

        $ mvn jar:jar
        
        
    4. install

      copy jar package to local repo. It has 3 goals: help, install, install-file

      Suppose you develop your own package and it does not exist in the central repository. And your another project wants to use this .jar.

      Modify the local repo location. Go to the maven installation directory, open the conf/setting.xml. add <localReposity>new_path<>/localReposity>

      1. Copy the project's package to the local repo

        $ mvn install:install
        # just run the single goal would cause error, run mvn jar:jar install:install. First generate the package, then install.
        
      2. Copy the project's package to the local repo

        $ mvn install:install-file -Dfile=... [-DpomFile]
        # may used to install an unofficial package
        
      3. mvn exec:java -Dexec.mainClom.iot.platform.Server" exec plugin http://blog.csdn.net/qbg19881206/article/details/19850857

  5. Build Lifecycle

    Maven project has 3 independent lifecycles: default, clean, and site

    The default lifecycle has 7 phases.

    1. validate:
    2. compile:
    3. test: run the test case
    4. package:
    5. verify: beside test, it also package the project. [== package]
    6. install: install package in the local repo.
    7. deploy: copy package to the remote repo.
    8. [clean]

    To process each maven lifecycle, just input mvn lifecycle e.g. mvn validate.

    *** These commands are not plugins, it is a combination of different plugin-goals defined by Maven***

    e.g. mvn compile is a combination of the resources:resources and compiler:compile.

    Site lifecycle:

    1. pre-site:
    2. site:
    3. post-site:
    4. site-deploy:

    Use plug-ins

    Plug-ins:goals can be binded to a phase. For example, when using mvn install, also run clean:clean.

        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-source-plugin</artifactId>
                    <version>2.4</version>
                    <executions>
                        <execution>
                            <phase>package</phase>
                            <goals>
                                <goal>help</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    

    Add a new build tag (build tag defines info about building process). Inside, defining plugins to select plug-ins. And an execution specifies which goal should be run.

    The goal will run after other pre-defined goals.

    For example, the above configuration will print help message after mvn package

  6. Dependency rules

    Short path high priority

    For example, when A depends on B.jar and C.jar. B.jar depends on D.jar. D depends on X.1.jar and C depends on X.2.jar

        A => B =>D => X.1
        A => C => X.2
    

    Then the project would have A, B, C, D, and X.2 not X.1

    First come First use

        A => B => X.1
        A => C => X.2 
    

    In the POM, if the dependency B is ahead of the dependency C, then the project has A, B, C, and X.1

  7. Aggregation & Inheritance

    Aggregation

    Put mutliple POM together. Each POM represent a sub-module, now put the together.

    Define a new POM, <modules></modules>

    Inheritance

    For example, every module would use junit. The define a parent POM.

    1. Put common dependencies in the <dependencyManagement
    2. <packaging> is pom not jar
    1. In the sub POM, add a <parent> tag to include the parent identifer (groupId, artifactId, and version)
  8. Examples

    Thrift

    Java thrift project would depend on the libthrift jar.

        <dependency>
            <groupId>org.apache.thrift</groupId>
            <artifactId>libthrift</artifactId>
            <version>0.10.0</version>
            <scope>compile</scope>
        </dependency>