[JAVA] Maven basic study notes

I've been using Gradle for a long time, but I have to use Maven for work, so I'm studying.

What is Maven

Java build tool. OSS. It seems to have been created as an alternative to Apache Ant.

The reading is "Maven" or "Maven" (I am a Maven school).

It's been around for a long time [^ 1], but it's still under development, and I get the impression that there are many projects that use Maven. As of 2020, Maven or Gradle is often the choice for Java build tools (I think).

[^ 1]: Maven 1.0 in 2004, Maven 2.0 in 2005, Maven 3.0 in 2010 (Maven – Maven Releases History)

The major version as of 2020 is 3. Maven 1 and 2 are not compatible, but 2 and 3 are still compatible.

environment

>mvn --version
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: ...\bin\..
Java version: 11.0.6, vendor: AdoptOpenJDK, runtime: ...
Default locale: ja_JP, platform encoding: MS932
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"

Installation

-Download the archive (ʻapache-maven-X.X.X-bin.zip`) from Official Site --Unzip at a suitable place

State after defrosting


`-apache-maven-X.X.X/
  |-bin/
  |-boot/
  |-conf/
  |-lib/
  |-LICENSE
  |-NOTICE
  `-README.txt

--Pass the path to % MAVEN_HOME% \ bin --Installation is completed when the version information is displayed by executing the following command.

Confirmation of installation


>mvn --version
Apache Maven X.X.X (...)
...

setting file

Common settings across projects can be described in one of the following files:

[^ 2]: % USERPROFILE% is a Windows environment variable that points to the user's home (for Linux, it means $ HOME).

The contents set in the former file are common to all projects across users. The contents set in the latter file are common across projects within the user.

The former file is in the downloaded zip, but all settings are empty and explained in the comments. The latter file does not exist at first, so it is better to copy the former file.

Proxy settings

settings.xml


<settings ...>
  ...
  <proxies>
    <proxy>
      <id>optional</id>
      <active>true</active>
      <protocol>http</protocol>
      <username>proxyuser</username>
      <password>proxypass</password>
      <host>proxy.host.net</host>
      <port>80</port>
      <nonProxyHosts>local.net|some.host.com</nonProxyHosts>
    </proxy>
  </proxies>
  ...
</settings>

Rewrite the required settings and write them in one of the above settings.xml.

Hello World

Generate a project

--Open the command line in an appropriate folder and execute the following command.

> mvn archetype:generate

--For the first time, the following list will be displayed after various downloads and other processes have been performed.

...
Choose archetype:
1: internal -> org.appfuse.archetypes:appfuse-basic-jsf (AppFuse archetype for creating a web application with Hibernate, Spring and JSF)
2: internal -> org.appfuse.archetypes:appfuse-basic-spring (AppFuse archetype for creating a web application with Hibernate, Spring and Spring MVC)
3: internal -> org.appfuse.archetypes:appfuse-basic-struts (AppFuse archetype for creating a web application with Hibernate, Spring and Struts 2)
...
16: internal -> org.apache.maven.archetypes:maven-archetype-quickstart ()
...
57: internal -> org.fusesource.scalate.tooling:scalate-archetype-empty (Generates a Scalate empty web application)
58: internal -> org.fusesource.scalate.tooling:scalate-archetype-guice (Generates a Scalate Jog web application)
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 16:

--"Choose archetype is displayed and you are prompted to enter the archetype number to use. --For now, try selecting the default 16 (ʻorg.apache.maven.archetypes: maven-archetype-quickstart) (just press Enter to select the default number)

Define value for property 'groupId': : 【com.example】
Define value for property 'artifactId': : 【hello-world】
Define value for property 'version':  1.0-SNAPSHOT: :【】
Define value for property 'package':  com.example: :【】
Confirm properties configuration:
groupId: com.example
artifactId: hello-world
version: 1.0-SNAPSHOT
package: com.example
 Y: : 【y】

--You will be prompted to enter the basic information of the project to be created, so enter it appropriately. --In the above example, the part surrounded by [] is the content entered with the keyboard (the empty [] is the part entered without entering anything). ――The meaning of each is a great explanation --You will be asked if you want to create with the information you entered last, so if there is no problem, enter y and Enter --Successful if BUILD SUCCESS is displayed

Check the generated project

--A folder with the same name as the name specified by ʻartifactIdis created in the current folder. --If you created it in the above example, a folder calledhello-worldis created. --The contents of thehello-world` folder are as follows

hello-The contents of the world folder


hello-world/
|-pom.xml
`-src/
  |-main/java/
  | `-com/example/
  |    `-App.java
  `-test/java/
    `-com/example/
      `-AppTest.java

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example</groupId>
  <artifactId>hello-world</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>hello-world</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        ...
      </plugins>
    </pluginManagement>
  </build>
</project>

App.java


package com.example;

/**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
    }
}

--A simple Hello World program project has been generated

Compile and run

--Execute the following command to compile the source code

compile


> mvn compile

--Also, various download processes run for the first time (it should be faster because there will be no downloads after the second time) --Successful when "BUILD SUCCESS" is displayed --The compilation result of ʻApp.java is output underhello-world / target / classes /. --Execute with the following command

hello-Run world


> java -cp target\classes com.example.App
Hello World!

Description

Archetype

--The first mvn archetype: generate implements a mechanism called ** archetype ** that automatically generates a project from a template. --Here, the simplest maven-archetype-quickstart is selected to automatically generate the project.

POM Maven – Introduction to the POM

Maven settings are described in an XML file called pom.xml. POM is an abbreviation for Project Object Model.

Maven manages build targets in units called ** projects **. The POM is a file that describes various settings for the project.

Super POM POMs have a parent-child relationship, and there is a ** Super POM ** as the highest parent of all POMs. For example, the latest Super POM can be found on the next page.

Maven Model Builder – Super POM

If there is no setting in the POM of the project, the setting of the parent POM is basically inherited. In other words, the Super POM is a POM that describes the default settings that apply to all projects.

Minimum configuration POM

If you create a POM with the minimum configuration, the contents of pom.xml will be as follows.

Minimum configuration pom.xml


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

  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>
</project>

--Write the <project> tag at the top --At least the following four tags must be described in it. - <modelVersion> - <groupId> - <artifactId> - <version> --<modelVersion> specifies the version of POM ――This basically doesn't change, so I think you should specify this value for the time being. --<groupId>, <artifactId>, <version> define the information to uniquely identify the project. --The fully qualified name of the project will be <groupId>: <artifactId>: <version> --In other words, in the case of the above settings, ʻexample: hello: 1.0.0is the fully qualified name of this project. - --ForgroupId, specify a name that can identify the organization to which the project belongs or the superior project. --For example, many plugins provided by Maven have a groupId of ʻorg.apache.maven.plugins. --. May or may not be attached (junit etc. is not attached) --The value of groupId does not have to match the Java package structure of the project, but it is safer to match it for less confusion. - <artifactId> --Specify a name that identifies the project --For example, the compiler plugin provided by Maven is maven-compiler-plugin, which is ʻartifactId. - --version specifies the version of the project --groupId and ʻartifactId will uniquely identify the project, and version will identify the version. --Settings not described in this pom.xml are basically inherited from Super POM Ru [^ 3] --In other words, <url> https://repo.maven.apache.org/maven2 </ url> is adopted for the setting of <repository> that is not described. ――However, there are some settings that are not described in Super POM but are adopted by default (such as <packaging>). ――The story is awesome

[^ 3]: I think "<modelVersion>is also in Super POM", but unfortunately this is not inherited (it will cause an error if deleted)

Prefix representing development version

--There is no fixed numbering rule for the version number of the artifact (probably) --However, the version with -SNAPSHOT at the end has a special meaning. --A version with the -SNAPSHOT prefix indicates that it is a version under development. --The version under development indicates that the contents of the artifact (jar) may be updated. ――On the other hand, the version without SNAPSHOT basically represents the release version, and the contents are not updated (promise). ――It's just a promise, so it's not tied up by the mechanism --With the repository (Nexus) function described later, it is possible to control the release version so that it cannot be updated and SNAPSHOT can be updated.

variable

In pom.xml, variables can be referenced to avoid the problem of duplicating the same value in multiple places.

Project model variables

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>
  
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.8</version>
        <configuration>
          <target>
            <echo>project.groupId = ${project.groupId}</echo>
            <echo>project.artifactId = ${project.artifactId}</echo>
            <echo>project.version = ${project.version}</echo>
            <echo>project.build.directory = ${project.build.directory}</echo>
          </target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

――Somehow, a lot of them suddenly appeared, but the important points here are as follows.

Extract only important parts


            <echo>project.groupId = ${project.groupId}</echo>
            <echo>project.artifactId = ${project.artifactId}</echo>
            <echo>project.version = ${project.version}</echo>
            <echo>project.build.directory = ${project.build.directory}</echo>

--Echoing the values of some variables --The ones that are written around this are adding plugins to enable echo. --When you do this, you get:

Execution result


> mvn antrun:run
...
     [echo] project.groupId = example
     [echo] project.artifactId = hello
     [echo] project.version = 1.0.0
     [echo] project.build.directory = F:\tmp\maven\hello\target
...

--You can see that the part described by $ {variable reference expression} is replaced with the evaluation result of the expression and output. --All the variables referenced in this example are called ** Project Model Variables **. --In short, it refers to the value of the tag under <project> in pom.xml. --project.version refers to the value of<project> <version> --project.build.directory is not in this pom.xml but Super POM Declared in

Expression syntax

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>
  
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.8</version>
        <configuration>
          <target>
            <echo>project.class = ${project.class}</echo>
            <echo>project.getClass() = ${project.getClass()}</echo>
            <echo>plugins[0].artifactId = ${project.build.plugins[0].artifactId}</echo>
            <echo>plugins[1].artifactId = ${project.build.plugins[1].artifactId}</echo>
            <echo>plugins[2].artifactId = ${project.build.plugins[2].artifactId}</echo>
          </target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jdeps-plugin</artifactId>
        <version>3.1.2</version>
      </plugin>
    </plugins>
  </build>
</project>

Execution result


> mvn antrun:run
...
     [echo] project.class = class org.apache.maven.model.Model
     [echo] project.getClass() = ${project.getClass()}
     [echo] plugins[0].artifactId = maven-antrun-plugin
     [echo] plugins[1].artifactId = maven-jdeps-plugin
     [echo] plugins[2].artifactId = ${project.build.plugins[2].artifactId}

--The expression written in $ {...} basically allows you to refer to the property of the object separated by dots (.). --If you refer to a property named foo, the methodgetFoo ()(or ʻisFoo ()) is executed behind the scenes. --In other words, if you have Getter, you can refer to it by the corresponding property name (you can also refer to class) --However, you can only refer to properties, you cannot execute methods directly. --If the property is an array or List, you can use square brackets ([] ) to refer to the index. --If the expression cannot be evaluated successfully, it will be treated as just a string --The substance of the projectvariable is [org.apache.maven.model.Model](https://maven.apache.org/ref/current/maven-model/apidocs/org/apache/maven/model/Model" It is an instance of a class called .html) --ThisModel` instance is [ReflectionValueExtractor](https://github.com/apache/maven-shared-utils/blob/master/src/main/java/org/apache/maven/shared/utils/introspection/ReflectionValueExtractor" The expression is being evaluated by being passed to .java # L163)

Map reference

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...
  
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.8</version>
        <configuration>
          <target>
            <echo>${project.build.pluginsAsMap(org.apache.maven.plugins:maven-antrun-plugin).id}</echo>
            <echo>${project.build.pluginsAsMap(org.apache.maven.plugins:maven-jdeps-plugin).id}</echo>
          </target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jdeps-plugin</artifactId>
        <version>3.1.2</version>
      </plugin>
    </plugins>
  </build>
</project>

Execution result


> mvn antrun:run
...
     [echo] org.apache.maven.plugins:maven-antrun-plugin:1.8
     [echo] org.apache.maven.plugins:maven-jdeps-plugin:3.1.2

--If the property is Map, you can refer to the key specification in the form offooMap (<key>). --<key> does not need to be enclosed in double quotation marks (" ), and is used as it is as the key of String. --The property pluginsAsMap is a class called PluginContainer Refers to the method defined in --This Map has [Plugin # getKey ()](https://maven.apache.org/ref/3.6.3/maven-model/apidocs/org/apache/maven/model/Plugin.html" as the key. As a result of # getKey-), the Plugin instance corresponding to the value is set. --Plugin # getKey () returns the value of the plugin's groupId and ʻartifactId connected by a colon (: ). --The [Build](https://maven.apache.org/ref/3.6.3/maven-model/apidocs/org/apache/maven/model/Build.html) class that can be referenced in project.buildis It inherits from thisPluginContainer --As you can see, some classes provide properties that convertList to Mapformat. --Specifically, the following class provides~ AsMap` - PluginContainer#getPluginsAsMap() - Plugin#getExecutionsAsMap() - Reporting#getReportPluginsAsMap() - ReportPlugin#getReportSetsAsMap()

Properties of each class

The overall picture of each class and property that can be referenced from Model is summarized in the class diagram.

maven.jpg

- Red line inherits </ font> - A single reference with a blue line </ font> - Green line is the reference in List </ font>

Special variables

--There are some variables that are not included in the project model but are specially defined and can be referenced.

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...
  
  <build>
    ...
          <target>
            <echo>project.basedir = ${project.basedir}</echo>
            <echo>project.baseUri = ${project.baseUri}</echo>
            <echo>maven.build.timestamp = ${maven.build.timestamp}</echo>
          </target>
    ...
  </build>
</project>

Execution result


     [echo] project.basedir = F:\tmp\maven\hello
     [echo] project.baseUri = file:///F:/tmp/maven/hello/
     [echo] maven.build.timestamp = 2020-03-04T13:45:10Z

--The following three are variables that are implicitly defined as ** Special Variables **. - project.basedir --Folder of the project itself - project.baseUri --project.basedir as a URI - maven.build.timestamp --Runtime Timestamp (UTC)

Specify the time stamp format

--By declaring the property maven.build.timestamp.format, you can specify the format of maven.build.timestamp arbitrarily. --The format format follows SimpleDateFormat.

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <properties>
    <maven.build.timestamp.format>yyyy/MM/dd HH:mm:ss</maven.build.timestamp.format>
  </properties>
  
  <build>
    ...
            <echo>maven.build.timestamp = ${maven.build.timestamp}</echo>
    ...
  </build>
</project>

Execution result


     [echo] maven.build.timestamp = 2020/03/04 13:49:49+00:00

Property

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <properties>
    <foo>FOO!!</foo>
    <fizz.buzz>FIZZ.BUZZ!?</fizz.buzz>
    <hoge-fuga>HOGE-FUGA??</hoge-fuga>
  </properties>
  
  <build>
    ...
            <echo>foo = ${foo}</echo>
            <echo>fizz.buzz = ${fizz.buzz}</echo>
            <echo>hoge-fuga = ${hoge-fuga}</echo>
            <echo>FOO = ${FOO}</echo>
    ...
  </build>
</project>

Execution result


     [echo] foo = FOO!!
     [echo] fizz.buzz = FIZZ.BUZZ!?
     [echo] hoge-fuga = HOGE-FUGA??
     [echo] FOO = ${FOO}

--You can declare your own variables in the <properties> tag --You can include - and . in the name --Case sensitive

Environment variable

xml.pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...
  
  <build>
    ...
            <echo>hoge = ${env.hoge}</echo>
            <echo>Hoge = ${env.Hoge}</echo>
            <echo>HOGE = ${env.HOGE}</echo>
    ...
  </build>
</project>

Execution result(When running on Windows)


> set Hoge=Hello

> mvn antrun:run
...
     [echo] hoge = ${env.hoge}
     [echo] Hoge = ${env.Hoge}
     [echo] HOGE = Hello
...

Execution result(When running on Linux)


$ export Hoge=Hello

$ mvn antrun:run
...
     [echo] hoge = ${env.hoge}
     [echo] Hoge = Hello
     [echo] HOGE = ${env.HOGE}

-- $ {env. Environment variable name} can be used to refer to the value of the OS environment variable. --When running on Windows, the variable name of ʻenvis ** normalized with all uppercase letters ** --That is, even if the name of the environment variable declared on Windows isPath, it must be capitalized as $ {env.PATH} `when referenced on pom.xml. ――It's just a story on Windows, and when running on Linux, specify it with the same name that is case-sensitive. ――Well, I think that it is common to declare environment variables in all capital letters, so if you write pom.xml in all capital letters, you will not have an accident.

System properties

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...
  
  <properties>
    <foo.bar>foo-bar</foo.bar>
    <fizz.buzz>fizz-buzz</fizz.buzz>
  </properties>

  <build>
    ...
            <echo>java.version = ${java.version}</echo>
            <echo>java.vm.vendor = ${java.vm.vendor}</echo>
            <echo>foo.bar = ${foo.bar}</echo>
            <echo>fizz.buzz = ${fizz.buzz}</echo>
    ...
  </build>
</project>

Execution result


> mvn antrun:run -Dfoo.bar=FOO-BAR
...
     [echo] java.version = 11.0.6
     [echo] java.vm.vendor = AdoptOpenJDK
     [echo] foo.bar = FOO-BAR
     [echo] fizz.buzz = fizz-buzz

--Java system properties (values that can be obtained with System.getProperties ()) can be referenced as they are with $ {system property name}. --If a property with the same name is declared in <properties>, the value specified in the system property takes precedence.

Repository

--One of the important components of Maven is ** Repository ** --In Maven, the artifacts of the created project are saved and managed in the repository. --The actual artifact is usually a jar file created by building the project.

Central repository

--There are two types of repositories --Local repository --Remote repository --There is a remote repository used by default called Central Repository (https://repo.maven.apache.org/maven2). -If you open the link above with a browser, you can see that various subdirectories exist. --If you follow the directory properly, you will finally reach the directory where the jar file is located. --For example, in this, ver 5.2.4.RELEASE of Spring Framework core is placed. Become a directory --As you can see, the central repository contains various OSS artifacts from around the world. --The central repository is managed by a company called Sonatype. --Anyone can publish their OSS in the central repository by applying (free of charge) --However, the application is in English --The unit of application is for each groupId --If you search for "Maven Central Repository Publishing Procedure", you will find various commentary articles. --Since it is difficult to search the central repository opened directly in the browser, usually use a search site such as Maven Repository: Search / Browse / Explore. --Alternatively, refer to the information written on the official page of the library you want to use.

Dependency resolution

--One of Maven's powerful features is dependency resolution. --In pom.xml, the artifacts used by the project can be defined as dependencies as follows:

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <dependencies>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.9</version>
    </dependency>
  </dependencies>
</project>

--<dependency> under <dependencies> points to an artifact --If you declare it like this, Maven will automatically download the artifacts declared with <dependencies> from the remote repository when you build the project and add them to your classpath. ――In other words, you can save the trouble of dropping the library by hand. --In addition, the artifacts stored in the repository also contain their own pom.xml. --If there are more <dependencies> in the pom.xml of the artifact specified in the project, Maven will automatically download those dependent artifacts as well. ――In other words, it is a mechanism that resolves all dependencies to the Imozuru formula. --Maven makes managing dependent libraries much easier thanks to this mechanism. --Maven's predecessor, Apache Ant, was very painful because it had to manage dependencies manually. --This mechanism is also used in Gradle, a latecomer to Maven.

Local repository

--Artif and meta information (such as pom.xml) downloaded from remote repositories are cached locally on the machine running Maven --This cache destination is called ** local repository ** ――If you access the remote repository every time you build, it will take a long time and you will not be able to build in an environment where the network is not available. --Therefore, Maven is supposed to search the local repository first. --If the desired artifact does not exist in the local repository, it will go to the remote repository for searching. --If you find an artifact in the remote repository, download it and save it in your local repository --This allows you to build a project without network access, as you only need to refer to the local repository from the second time onwards. --The local repository location defaults to % USERPROFILE% \ .m2 \ repository --For Linux OS, $ HOME / .m2 / repository --Artifs cached in the local repository will remain if nothing is done --Unless there is a reason such as running out of disk space, there is no need to erase it.

Private repository

--You can build your own remote repository using an OSS application called Nexus Repository OSS. --Nexus is developed by Sonatype, which manages the central repository. --There is a paid version and a free OSS version --For example, if you have an artifact that you want to share only within your company, you can easily use it as a private repository by building a Nexus server within your intranet. --The remote repository to use can be specified in pom.xml as follows: --Host name and port number need to be adjusted according to the actual environment

Pom when a remote repository is specified.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <repositories>
    <repository>
      <id>my-private-repository</id>
      <name>My Private Repository</name>
      <url>http://private.repository.host/repository</url>
      <layout>default</layout>
    </repository>
  </repositories>
</project>

--In addition, Nexus also acts as a proxy for other remote repositories. ――For example, suppose you have the following configuration --Build the Nexus repository as a proxy for the central repository --Set Nexus repository as remote repository in pom.xml --If the project has dependent artifacts, Maven will first search the local repository --If it is not in the local repository, then search for the Nexus repository you specified as the remote repository. --Nexus searches the central repository if it is not in the Nexus repository either --And it returns the artifacts downloaded from the central repository to Maven --At this time, the Nexus repository internally caches the artifacts downloaded from the central repository. --If a search request for the same artifact comes in, it will return the cached artifact. ――This will allow you to reduce network traffic, or even if the Internet is not connected due to some kind of failure, you can resolve the dependency by connecting to the Nexus repository in the intranet.

** Proxy image **

maven.jpg

Plugin (basic)

In Maven, all processing is done by ** Plugin **.

For example, the process for compiling Java source code is provided by maven-compiler-plugin.

The basic plugins provided by the Maven project itself can be found in the list at Maven – Available Plugins.

Plugin Goal

--Individual tasks (processes) defined in the plugin are called ** Goal **. --Refer to the documentation of each plugin to find out what goals the plugin you want to use has. --Goals defined in maven-jdeps-plugin - jdkinternals - test-jdkinternals --Goals defined in maven-jar-plugin - jar - test-jar

How to execute a goal

There are two main ways to execute the goals of a plugin.

  1. Specify directly on the command line and execute
  2. Execute in association with the phase

The method of linking to the second phase is set aside, and the method of directly specifying 1 is confirmed first.

Fully qualified name specification

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>
</project>

Run the jdeps plugin


> mvn org.apache.maven.plugins:maven-jdeps-plugin:3.1.2:jdkinternals
...
classes -> java.base
   example          -> java.io            java.base
   example          -> java.lang          java.base
...

--I'm passing some lengthy arguments to the mvn command --This specifies the fully qualified name and goal name of the previous maven-jdeps-plugin. --In the format, it looks like <fully qualified name>: <goal name> --<fully qualified name> is here ʻorg.apache.maven.plugins: maven-jdeps-plugin: 3.1.2, --becomesjdkinternals` --If you specify a fully qualified name, the plugin jar file is fetched from the repository based on that information and the goal is executed.

prefix specification (when there is no plug-in setting)

――Since it is difficult to enter the fully qualified name every time, you can also omit the following description.

If omitted


> mvn jdeps:jdkinternals
...
classes -> java.base
   example          -> java.io            java.base
   example          -> java.lang          java.base
...

--This is how to specify the format <prefix>: <goal name> --Whether it is a fully qualified name specification or a prefix specification is distinguished by the number of colons (:) [^ 4] --If there are three :, specify with the fully qualified name groupId: artifactId: version: goal. --If there are two :, specify groupId: artifactId: goal without the version number. --If there is only one :, specify it with the prefix prefix: goal. --If prefix is specified, the fully qualified name will be resolved as follows. --First, let groupdId be one of the following: - org.apache.maven.plugin - org.codehaus.mojo --Next, look at the metadata (maven-metadata.xml) for each groupId -maven-metadata.xml in org.apache.maven.plugin -org.codehaus.mojo maven-metadata.xml --If you look at the contents of maven-metadata.xml, you can see that the correspondence of prefix is listed for each ʻartifactId`.

xml:org.apache.maven.plugin maven-metadata-xml


<?xml version="1.0" encoding="UTF-8"?>
<metadata>
  <plugins>
    <plugin>
      <name>Apache Maven ACR Plugin</name>
      <prefix>acr</prefix>
      <artifactId>maven-acr-plugin</artifactId>
    </plugin>
    ...
    <plugin>
      <name>Apache Maven JDeps Plugin</name>
      <prefix>jdeps</prefix>
      <artifactId>maven-jdeps-plugin</artifactId>
    </plugin>
    ...
  </plugins>
</metadata>

--Find a prefix in this maven-metadata.xml that matches the prefix specified on the command line, and set that<artifactId>to ʻartifactId. --The prefix specified on the command line is jdeps, so maven-jdeps-plugin becomes ʻartifactId --Next, check the metadata (maven-metadata.xml) for each ʻartifactId` -maven-metadata.xml of maven-jdeps-plugin

maven-jdeps-plugin maven-metadata.xml


<?xml version="1.0" encoding="UTF-8"?>
<metadata>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-jdeps-plugin</artifactId>
  <versioning>
    <latest>3.1.2</latest>
    <release>3.1.2</release>
    <versions>
      <version>3.0.0</version>
      <version>3.1.0</version>
      <version>3.1.1</version>
      <version>3.1.2</version>
    </versions>
    <lastUpdated>20190619052916</lastUpdated>
  </versioning>
</metadata>

--Set the value set in the release version (<release>) to version --If there is no release version, set the latest version (<latest>) [^ 5] to version --The groupId, ʻartifactId, versiondetermined above are fully qualified names. -groupId:org.apache.maven.plugin -artifactId:maven-jdeps-plugin -version:3.1.2`

[^ 4]: Strictly speaking, even if you specify something like compiler :::: compile, it will be judged as a prefix specification, but for the sake of clarity, the number of colons is used here (for details, [MojoDescriptorCreator implementation] See](https://github.com/apache/maven/blob/maven-3.6.3/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoDescriptorCreator.java#L141) )

[^ 5]: <release> is the latest version in the release version, while <latest> refers to the latest version, including snapshots.

Explicitly set the plugin

-In the method of ↑, the version of the plug-in is decided based on the metadata. --Maybe you will use the latest version when a new version comes out, but if you can not fix the movement, the build may become unstable --Therefore, normally, the version of the plug-in used for each project is fixed. --In the case of ↑, prefix can be specified only when groupId is either ʻorg.apache.maven.plugin or ʻorg.codehaus.mojo [^ 6] --If you want to use plugins of groupId other than these by specifying prefix, you need to explicitly set the plugin.

[^ 6]: Strictly speaking, you can add the groupId to be searched by<pluginGroups>in settings.xml (Reference: Introduction to Plugin Prefix Resolution guides / introduction / introduction-to-plugin-prefix-mapping.html # Configuring_Maven_to_Search_for_Plugins))

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <build>
    <plugins>
      <plugin>
        <groupId>org.asciidoctor</groupId>
        <artifactId>asciidoctor-maven-plugin</artifactId>
        <version>1.5.8</version>
      </plugin>
    </plugins>
  </build>
</project>

--Individual plugins are set with the <plugin> tag --<plugin> is listed under <build> <plugins> --Specify the fully qualified name of the plugin with <groupId>, <artifactId>, <version> --Here, Asciidoctor Maven Plugin is set. --This setting locks the version of ʻasciidoctor-mavne-pluginto1.5.8`.

asciidoctor-maven-Running plugin


> mvn asciidoctor:process-asciidoc
...
[INFO] BUILD SUCCESS
...

Resolve prefix specification (if plugin is specified)

-When the plugin is specified by <plugin> as in ↑, the method of resolving the fully qualified name from the prefix specification changes a little. --First, Maven checks the plugin.xml of each plugin that is explicitly set in pom.xml. --Usually plugin.xml is stored under META-INF / maven in the plugin jar --For example, the plugin.xml of ʻasciidoctor-mavne-plugin` looks like this:

asciidoctor-maven-plugin plugin.xml


<?xml version="1.0" encoding="UTF-8"?>

<!-- Generated by maven-plugin-tools 3.5 on 2019-03-30 -->

<plugin>
  <name>Asciidoctor Maven Plugin and Doxia Parser</name>
  <description>Asciidoctor Maven Plugin and Doxia Parser (for Maven Site integration)</description>
  <groupId>org.asciidoctor</groupId>
  <artifactId>asciidoctor-maven-plugin</artifactId>
  <version>1.5.8</version>
  <goalPrefix>asciidoctor</goalPrefix>
  <isolatedRealm>false</isolatedRealm>
  <inheritedByDefault>true</inheritedByDefault>
  ...

--The important thing here is the value set in <goalPrefix> --The plugins groupId and ʻartifactIdwhose value is equal to the prefix specified on the command line are adopted. --Finally,version is determined as follows --If specified in pom.xml, that version will be adopted --If not specified, it is determined from the metadata (maven-metadata.xml) for each ʻartifactId (same method as when no plugin is specified).

Relationship between artifactId and prefix

--In the explanation so far, you can see that ʻartifactIdand prefix are essentially unrelated. --The prefix is determined byinmaven-metadata.xml or in plugin.xml. --However, the plugins that actually exist have the following relationship between ʻartifactId and prefix. --For official plugins provided by the Maven project --If ʻartifactId is maven-XXX-plugin, XXX is the prefix --For other plugins --If ʻartifactId is XXX-maven-plugin, XXX is the prefix ――These are the results of such a naming rule being recommended, and it does not mean that you cannot make a plugin without this name. --If you want to make it, you can also make a plugin with ʻartifactIdthat is completely different from this naming rule. -** However, the namemaven-XXX-plugin is meant to indicate that it is an official Maven plugin, so be careful as non-official use of this name will result in trademark infringement ** - [Important Notice: Plugin Naming Convention and Apache Maven Trademark](https://maven.apache.org/guides/plugin/guide-java-plugin-development.html#Important_Notice:_Plugin_Naming_Convention_and_Apache_Maven_Trademark) --Unusual naming is not beneficial because it only confuses users, so if you make your own plugin, it is safe to use ʻartifactId as XXX-maven-plugin unless you have a specific reason. ――So, ʻartifactId and prefix are not essentially related, but it is safe to think that they are related in practice (I think). --So, if ʻartifactId is foo-maven-plugin, you can think of prefix as foo (I think) --Conversely, if the prefix is foo, you can think of ʻartifactId as foo-maven-plugin` (if it's not a plugin provided by the Maven project).

Plugin settings (parameters)

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.8</version>
        <configuration>
          <target>
            <echo>Hello World!!</echo>
          </target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Execution result


> mvn antrun:run
...
main:
     [echo] Hello World!!
...

--Plugin settings (** parameters **) can be described with the <configuration> tag under <plugin> --The tags that can be specified under <configuration> are different for each plugin goal. --Here we are using a plugin called maven-antrun-plugin --This plugin has the goal of run --You can see that the parameter that can be specified by <configuration> is listed on the description page of the run goal. --For plugins with multiple goals, the parameters specified in <configuration> will be applied to all goals.

Check the plugin description

--You can check what kind of goals the plugin has and what parameters can be specified by looking at the explanation page of each plugin. --However, if you have trouble opening each page, you can check it with maven-help-plugin.

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.8</version>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-help-plugin</artifactId>
        <version>3.2.0</version>
        <configuration>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-antrun-plugin</artifactId>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Execution result


> mvn help:describe
...
Name: Apache Maven AntRun Plugin
Description: Runs Ant scripts embedded in the POM
Group Id: org.apache.maven.plugins
Artifact Id: maven-antrun-plugin
Version: 1.8
Goal Prefix: antrun

This plugin has 2 goals:

antrun:help
  Description: Display help information on maven-antrun-plugin.
    Call mvn antrun:help -Ddetail=true -Dgoal=<goal-name> to display parameter
    details.

antrun:run
  Description: Maven AntRun Mojo.
    This plugin provides the capability of calling Ant tasks from a POM by
    running the nested Ant tasks inside the <tasks/> parameter. It is
    encouraged to move the actual tasks to a separate build.xml file and call
    that file with an <ant/> task.

For more information, run 'mvn help:describe [...] -Ddetail'
...

-By executing the goal describe, you can describe the plugin specified by <configuration>. Can be confirmed --<groupId> and <artifactId> allow plugins to be identified as maven-antrun-plugin -- describe As you can see from the goal description page, you can use <goal> to narrow down the goal and <detail> to output details (parameters that can be specified for each goal).

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <build>
    <plugins>
      ...
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-help-plugin</artifactId>
        <version>3.2.0</version>
        <configuration>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-antrun-plugin</artifactId>
          <goal>run</goal>
          <detail>true</detail>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Execution result


> mvn help:describe
...
antrun:run
  Description: Maven AntRun Mojo.
    ...
  Implementation: org.apache.maven.plugin.antrun.AntRunMojo
  Language: java

  Available parameters:

    ...

    target
      The XML for the Ant target. You can add anything you can add between
      <target> and </target> in a build.xml.

    ...
...

-Although the example of ↑ is omitted, all parameters are output with explanations.

Specified in system properties

--The parameters specified in <configuration> of help: describe can also be specified from the system properties.

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <build>
    <plugins>
      ...
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-help-plugin</artifactId>
        <version>3.2.0</version>
      </plugin>
    </plugins>
  </build>
</project>

Execution result


> mvn help:describe -Dplugin=antrun
...
Name: Apache Maven AntRun Plugin
Description: Runs Ant scripts embedded in the POM
Group Id: org.apache.maven.plugins
Artifact Id: maven-antrun-plugin
Version: 1.8
Goal Prefix: antrun

This plugin has 2 goals:

antrun:help
  Description: Display help information on maven-antrun-plugin.
    ...

antrun:run
  Description: Maven AntRun Mojo.
    ...

For more information, run 'mvn help:describe [...] -Ddetail'
...

---Dplugin = antrun is specified as a system property when executing Maven --Refer to Documentation for the description of the plugin parameter. --As you can see, some goal parameters can be passed as system properties. --Not all parameters can be specified in system properties --Whether a parameter can be specified in a system property can be checked by checking whether the parameter's document contains ** User property **. --For example, the plugin parameter documentation says ʻUser Property: plugin. Can be confirmed --This means that you can specify a value with a property named plugin. --Parameter names and property names do not always match ** --pluginjust happens to match, like [antrun skip](https://maven.apache.org/plugins/maven-antrun-plugin/run-mojo.html#skip) Some are not --Here, ** properties ** means that you can specify not only system properties but also` on pom.xml.

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <properties>
    <plugin>jdeps</plugin>
  </properties>

  <build>
    <plugins>
      ...
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-help-plugin</artifactId>
        <version>3.2.0</version>
      </plugin>
    </plugins>
  </build>
</project>

--In <properties>, jdeps is set in plugin.

Execution result (when plugin is not specified in the system property)


> mvn help:describe
...
Name: Apache Maven JDeps Plugin
Description: The JDeps Plugin uses the jdeps tool to analyze classes for
  internal API calls.
Group Id: org.apache.maven.plugins
Artifact Id: maven-jdeps-plugin
Version: 3.1.2
Goal Prefix: jdeps
...

Execution result (when plugin is specified in the system property)


> mvn help:describe -Dplugin=antrun
...
Name: Apache Maven AntRun Plugin
Description: Runs Ant scripts embedded in the POM
Group Id: org.apache.maven.plugins
Artifact Id: maven-antrun-plugin
Version: 1.8
Goal Prefix: antrun
...

--If no system properties are specified, the value specified by <properties> (jdeps) is adopted. --If you specify a system property, that value (ʻantrun`) is adopted.

Life cycle and phase

――Even if you say "build" in a nutshell, its contents include various processes. --For example, to build a simple Java program, the following processing can be considered.

  1. Compile the source code
  2. Collect resource files
  3. Compile the test code
  4. Collect resource files for testing
  5. Run the test code
  6. Package the compilation results and resource files together in an archive such as a jar.
  7. Store the archive in place --In Maven, each of these processes is called ** Phase **. --And the set of phases is called ** Lifecycle **

Built-in life cycle

--Maven has the following three life cycles as standard - default - clean - site

default life cycle

--default life cycle defines the life cycle from building and deploying a project --The default life cycle consists of the following phases: 1. validate 2. initialize 3. generate-sources 4. process-sources 5. generate-resources 6. process-resources 7. compile 8. process-classes 9. generate-test-sources 10. process-test-sources 11. generate-test-resources 12. process-test-resources 13. test-compile 14. process-test-classes 15. test 16. prepare-package 17. package 18. pre-integration-test 19. integration-test 20. post-integration-test 21. verify 22. install 23. deploy

clean life cycle

--clean life cycle defines a life cycle to delete project artifacts --clean The life cycle consists of the following phases 1. pre-clean 2. clean 3. post-clean

site life cycle

--site life cycle defines the life cycle of project website generation --The site life cycle consists of the following phases: 1. pre-site 2. site 3. post-site 4. site-deploy

Relationship between phases and plugin goals

――The goal of the plug-in to be executed in that phase is linked to each phase of the life cycle.

clean, site For life cycle

--For example, in the clean life cycle and the site life cycle, the goals are linked as follows:

** clean plugin **

Phase Plugin goal
pre-clean - -
clean maven-clean-plugin clean
post-clean - -

** site plugin **

Phase Plugin goal
pre-site - -
site maven-site-plugin site
post-site - -
site-deploy maven-site-plugin deploy

--That is, running the clean phase will run the clean goal of the maven-clean-plugin.

For default life cycle

--In the case of the default life cycle, the link between the phase and the goal is not fixed. --The goals executed in the default life cycle depend on the ** packaging ** of the project

packaging -Packaging is a setting value that determines how to package the project, and one of the following values can be specified. - pom - jar - ejb - maven-plugin - war - ear - rar --This packaging is specified on pom.xml as follows

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...
  <packaging>jar</packaging>
  ...
</project>

--Here, jar is specified as packaging. --The <packaging> tag can be omitted in pom.xml. --If omitted, the default is jar

Goals for each packaging

--default The goals associated with the life cycle phases differ depending on the packaging as follows: --As an example, the goals associated with pom and jar are as follows: --Since there are many phases, the phases that are not associated with anything are excluded (validate etc.) --For packaging other than these, refer to Maven Core – Plugin Bindings for Default Lifecycle Reference etc.

pom

Phase Plugin goal
install maven-install-plugin install
deploy maven-deploy-plugin deploy

jar

Phase Plugin goal
process-resources maven-resources-plugin resources
compile maven-compiler-plugin compile
process-test-resources maven-resources-plugin testResources
test-compile maven-compiler-plugin testCompile
test maven-surefire-plugin test
package maven-jar-plugin jar
install maven-install-plugin install
deploy maven-deploy-plugin deploy

Perform a phase

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>
</project>

Run the test phase


> mvn test
...
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello ---
...
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ hello ---
...
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hello ---
...
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ hello ---
...
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ hello ---
...

--Phase can be executed by specifying it as an argument of mvn command. --Here, I'm trying to run the test phase in a project whose packaging is jar. --packaing defaults to jar because the description of<packaing>is omitted. --If you specify a phase and execute it, all the phases before that phase will also be executed in order. --For example, the test phase is preceded by phases such as validate, process-resources, and test-compile. --In the above example, you can see that maven-resources-plugin: resources, maven-compiler-plugin: compile, ... are executed. --When a phase is executed, all goals associated with that phase are executed. --maven-resources-plugin: resources The goal is in the resources phase, maven-compiler-plugin: compile The goal is tied to the compile phase

Execute by specifying multiple phases and goals

> mvn clean compiler:compile

--Multiple phases and goals can be specified in the mvn command and executed. --In this case, the execution order is clean compiler: compile. --In other words, it is executed in the order specified by the argument.

Associate goals with phases

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.8</version>
        <executions>
          <execution>
            <phase>validate</phase>
            <goals>
              <goal>run</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <target>
            <echo>Hello Antrun!!</echo>
          </target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Execution result


> mvn compile
...
[INFO] --- maven-antrun-plugin:1.8:run (default) @ hello ---
[INFO] Executing tasks

main:
     [echo] Hello Antrun!!
...
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello ---
...
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ hello ---
...

--Any goal can be linked to any phase --Phase and goal are linked with <execution> in the plugin settings. --Specify the phase with <phase> and specify the goal to be linked with <goals> <goal> --Here, the run goal of maven-antrun-plugin is associated with the validate phase. --As you can see from the structure <goals> <goal>, it is possible to link multiple goals of the same plugin to one phase.

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jdeps-plugin</artifactId>
        <version>3.2.6</version>
        <executions>
          <execution>
            <phase>verify</phase>
            <goals>
              <goal>jdkinternals</goal>
              <goal>test-jdkinternals</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

Execution result


> mvn verify
...
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello ---
...
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ hello ---
...
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hello ---
...
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ hello ---
...
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ hello ---
...
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ hello ---
...
[INFO] --- maven-jdeps-plugin:3.1.2:jdkinternals (default) @ hello ---
...
[INFO] --- maven-jdeps-plugin:3.1.2:test-jdkinternals (default) @ hello ---

--Linking jdkinternals and test-jdkinternals of maven-jdeps-plugin to the verify phase --If multiple goals are linked to one phase, those goals will be executed in the order declared on pom.xml [^ 7] --In other words, in the case of ↑ setting, it is executed in the order of jdkinternals test-jdkinternals. --You can change the execution order by changing the order of the <goal> tags.

Link to multiple phases

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.8</version>
        <executions>
          <execution>
            <id>foo</id>
            <phase>validate</phase>
            <goals>
              <goal>run</goal>
            </goals>
          </execution>
          <execution>
            <id>bar</id>
            <phase>compile</phase>
            <goals>
              <goal>run</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <target>
            <echo>Hello Antrun!!</echo>
          </target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Execution result


> mvn compile
...
[INFO] --- maven-antrun-plugin:1.8:run (foo) @ hello ---
...
     [echo] Hello Antrun!!
...
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello ---
...
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ hello ---
...
[INFO] --- maven-antrun-plugin:1.8:run (bar) @ hello ---
...
     [echo] Hello Antrun!!
...

--If you write multiple <execution> tags, you will be able to link goals to multiple phases. --If you specify more than one <execution>, you must also specify the <id> tag. --Set <id> to a unique value that can identify the <execution> --This value is output to the console at runtime ( (foo) part of maven-antrun-plugin: 1.8: run (foo)) --This is information to identify which <execution> was executed, so it is useful for debugging when the build does not go well. ――Therefore, it is better to give a descriptive name that is easy to identify.

Set for each execution

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.8</version>
        <executions>
          <execution>
            <id>foo</id>
            <phase>validate</phase>
            <goals>
              <goal>run</goal>
            </goals>
            <configuration>
              <target>
                <echo>VALIDATE!!</echo>
              </target>
            </configuration>
          </execution>
          <execution>
            <id>bar</id>
            <phase>compile</phase>
            <goals>
              <goal>run</goal>
            </goals>
            <configuration>
              <target>
                <echo>COMPILE!!</echo>
              </target>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

Execution result


> mvn compile
...
[INFO] --- maven-antrun-plugin:1.8:run (foo) @ hello ---
...
     [echo] VALIDATE!!
...
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello ---
...
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ hello ---
...
[INFO] --- maven-antrun-plugin:1.8:run (bar) @ hello ---
...
     [echo] COMPILE!!
...

--The <configuration> that describes the goal setting can also be specified for each <execution>. ――This makes it possible to divide the settings for each specific phase.

A special id that is adopted when the goal is executed directly

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.8</version>
        <executions>
          <execution>
            <id>default-cli</id>
            <configuration>
              <target>
                <echo>Hello @ default-cli</echo>
              </target>
            </configuration>
          </execution>
          <execution>
            <id>validate-phase</id>
            <phase>validate</phase>
            <goals>
              <goal>run</goal>
            </goals>
            <configuration>
              <target>
                <echo>Hello @ validate-phase</echo>
              </target>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

Execution result


> mvn antrun:run
...
     [echo] Hello @ default-cli
...

> mvn validate
...
     [echo] Hello @ validate-phase
...

--If you execute the goal directly, ʻid defaults to default-cli --Therefore, if you set ` with this value, you can describe the setting that is applied only when the goal is executed directly.

Execute by specifying id

--Since 3.3.1 of Maven, it is possible to execute the goal by specifying <id> of <execution>.

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.8</version>
        <executions>
          <execution>
            <id>default-cli</id>
            <configuration>
              <target>
                <echo>Hello default-cli!!</echo>
              </target>
            </configuration>
          </execution>
          <execution>
            <id>foo</id>
            <configuration>
              <target>
                <echo>Hello Foo!!</echo>
              </target>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

--The two <id>, default-cli and foo, define <execution>.

Execution result


> mvn antrun:run
...
     [echo] Hello default-cli!!

> mvn antrun:run@foo
...
     [echo] Hello Foo!!

--ʻAntrun: If you run only with run, default-cliwill be run better -By following the goal specification with@ , such as ʻantrun: run @ foo, the <execution> of the specified <id> is executed.

Default phase

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-checkstyle-plugin</artifactId>
        <version>3.1.1</version>
        <executions>
          <execution>
            <goals>
              <goal>check</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

Execution result


> mvn verify
...
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello ---
...
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ hello ---
...
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hello ---
...
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ hello ---
...
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ hello ---
...
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ hello ---
...
[INFO] --- maven-checkstyle-plugin:3.1.1:check (default) @ hello ---

--Adding maven-checkstyle-plugin to run the verify phase --In pom.xml, only <goal> check </ goal> is specified in <execution>, not <phase>. --However, if you look at the execution result, you can see that the check goal is executed in the verify phase. --Goals can define the phases associated with them by default. --If you look at the check goal description page, you can see that the default phase is verify. Recognize --If the phase is not specified in <execution>, it will be executed in the phase associated with this default. --If a goal has no phases associated with it, that goal can only be activated by specifying it directly on the command line.

Plugin version specification

--Plugins can be used to some extent without being explicitly set with <plugin> -Some basic plugins (such as maven-compiler-plugin) are automatically applied depending on the packaging settings --If a prefix is specified, groupId, ʻartifactId, versionwill be automatically resolved. --If it works without any settings, I feel like you don't have to write. --However, the method of executing without setting ` may change the version of the plugin every time it is executed. --For example, plugins that are automatically configured by packaging may change depending on the version of Maven. --For example, you can check the version of the plugin set in 3.6.3 at here. --If you don't have the same version of Maven that your developers are using, the build results may vary from developer to developer. -(In the first place, the version of the plugin set by default is old) --Also, the version of the plugin that is resolved by specifying the prefix is basically the latest in the repository. --Also, if the latest run time changes, the result may change. ――Therefore, it is basically good to specify the version of the plug-in to be used even if you think it is troublesome. --However, the pom.xml example described here may omit the plugin settings for the following reasons. ――When the amount of description increases, it makes me feel uncomfortable to read. --I can't pay attention to the necessary part (the part I'm trying to explain)

Parent-child relationship of the project

――You can have a parent-child relationship in the project

Folder structure


|-pom.xml
`-child/
  `-pom.xml

--Put the parent project pom.xml in the top folder and the child project pom.xml under the child folder

/pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>parent</artifactId>
  <version>1.0.0</version>
  <packaging>pom</packaging>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.8</version>
        <configuration>
          <target>
            <echo>artifactId = ${project.artifactId}</echo>
          </target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

--In the parent project's pom.xml, you must specify pom for<packaging>

/child/pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <parent>
    <groupId>example</groupId>
    <artifactId>parent</artifactId>
    <version>1.0.0</version>
  </parent>

  <artifactId>child</artifactId>
</project>

--In the child project pomx.ml, use <parent> to specify the parent --<parent> specifies groupId, ʻartifactId, versionto identify the parent POM --In a parent-child relationship project, the child POM inherits the parent POM --For this reason, settings not described in the child pom.xml will be inherited from the settings in the parent pom.xml. --Since the parent settings are inherited forand, the description is unnecessary in the child pom.xml. --However, ` must be specified as expected.

Execution result (top folder)


> mvn antrun:run
...
     [echo] artifactId = parent

Execution result (child folder)


> mvn antrun:run
...
     [echo] artifactId = child

--Since the setting of <plugins> is also inherited, the ʻantrun` plugin set in the parent project can be used in the child project as well.

How to solve the parent project

--Parent pom.xml set with <parent> is searched in the following order:

  1. If <relativePath> is specified, refer to pom.xml in that location
  2. If <relativePath> is not specified, refer to pom.xml of ** one level up **
  3. If not, search and browse the repository (local or remote) -In the example of ↑, the parent project was one above the child project, so the parent POM was found without specifying the location.

Specify the location of the parent project

--However, in the case of a folder structure like ↓, it is necessary to specify the path with <relativePath>.

Folder structure


|-parent/
| `-pom.xml
`-child/
  `-pom.xml

--parent and child are side by side, and pom.xml of the parent project does not exist one above the child project. --If you run Maven in a child project in this state, you will get the following error:

Execution result (child project)


> mvn antrun:run
...
[FATAL] Non-resolvable parent POM for example:child:1.0.0: Failure to find example:parent:pom:1.0.0 in https://repo.maven.apache.org/maven2 was cached in the local repository, resolution will not be reattempted until the update interval of central has elapsed or updates are forced and 'parent.relativePath' points at wrong local POM @ line 6, column 11
 @
...

--To solve this, you need to register the parent project jar in the repository or specify the location of the parent project with <relativePath> as shown below.

/child/pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  <modelVersion>4.0.0</modelVersion>

  <parent>
    <groupId>example</groupId>
    <artifactId>parent</artifactId>
    <version>1.0.0</version>
    <relativePath>../parent/pom.xml</relativePath>
  </parent>

  <artifactId>child</artifactId>
</project>

Execution result (child project)


> mvn antrun:run
...
     [echo] artifactId = child

--The parent project was found and worked

POM merge

--If the POM has a parent-child relationship, the parent POM will be merged into the child POM. --Let's see how the merge is done

Parent pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>parent</artifactId>
  <version>1.0.0</version>
  <packaging>pom</packaging>

  <properties>
    <hoge>PARENT</hoge>
    <fuga>PARENT</fuga>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.9</version>
    </dependency>
  </dependencies>

  <build>
    <resources>
      <resource>
        <directory>parent/dir</directory>
      </resource>
    </resources>

    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.8</version>
        <configuration>
          <target>
            <echo>hoge = ${hoge}</echo>
            <echo>fuga = ${fuga}</echo>
            <echo>piyo = ${piyo}</echo>
            <echo>dependencies[0].artifactId = ${project.dependencies[0].artifactId}</echo>
            <echo>dependencies[1].artifactId = ${project.dependencies[1].artifactId}</echo>
            <echo>resources[0].directory = ${project.build.resources[0].directory}</echo>
            <echo>resources[1].directory = ${project.build.resources[1].directory}</echo>
            <echo>plugins[0] = ${project.build.plugins[0].id}</echo>
            <echo>plugins[1] = ${project.build.plugins[1].id}</echo>
          </target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

--For verification, some settings are described so that the settings can be displayed by the ʻantrun` plugin.

Child pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <parent>
    <groupId>example</groupId>
    <artifactId>parent</artifactId>
    <version>1.0.0</version>
  </parent>

  <artifactId>child</artifactId>

  <properties>
    <fuga>CHILD</fuga>
    <piyo>CHILD</piyo>
  </properties>

  <dependencies>
    <dependency>
      <groupId>commons-codec</groupId>
      <artifactId>commons-codec</artifactId>
      <version>1.14</version>
    </dependency>
  </dependencies>

  <build>
    <resources>
      <resource>
        <directory>child/dir</directory>
      </resource>
    </resources>

    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jdeps-plugin</artifactId>
        <version>3.1.2</version>
      </plugin>
    </plugins>
  </build>
</project>

--It inherits the parent POM and describes so that some settings overlap.

Execution result (parent project)


> mvn antrun:run
...
     [echo] hoge = PARENT
     [echo] fuga = PARENT
     [echo] piyo = ${piyo}
     [echo] dependencies[0].artifactId = commons-lang3
     [echo] dependencies[1].artifactId = ${project.dependencies[1].artifactId}
     [echo] resources[0].directory = parent/dir
     [echo] resources[1].directory = ${project.build.resources[1].directory}
     [echo] plugins[0] = org.apache.maven.plugins:maven-antrun-plugin:1.8
     [echo] plugins[1] = ${project.build.plugins[1].id}

--First, try to output each setting value in the parent project --Of course, only the value set in the parent POM is output, and the value that is not set is output as it is without the expression being evaluated.

Execution result (child project)


> mvn antrun:run
...
     [echo] hoge = PARENT
     [echo] fuga = CHILD
     [echo] piyo = CHILD
     [echo] dependencies[0].artifactId = commons-codec
     [echo] dependencies[1].artifactId = commons-lang3
     [echo] resources[0].directory = child/dir
     [echo] resources[1].directory = ${project.build.resources[1].directory}
     [echo] plugins[0] = org.apache.maven.plugins:maven-antrun-plugin:1.8
     [echo] plugins[1] = org.apache.maven.plugins:maven-jdeps-plugin:3.1.2

--As a result of outputting in the child project, the setting of the child POM is adopted for the overlapping part (<properties> <fuga> etc.) in the single value setting. --On the other hand, the overlapping part (<dependencies>, <plugins>, etc.) in the setting of multiple values is based on the parent POM and the element of the child POM is added. --Basically, single-valued items are overwritten and multi-valued items (such as <plugins>) are added with elements. --However, there are some exceptions, for example, <build> <resources> is a multi-valued item but is overwritten. -Official documentation states that <resources> is also subject to merging, but in reality Overwritten --In terms of implementation, [ModelMerger](https://github.com/apache/maven/blob/maven-3.6.3/maven-model/src/main/java/org/apache/maven/model/merge/ModelMerger It seems that POM is being merged in a class called .java) --[MergeBuildBase_Resources ()] of this class (https://github.com/apache/maven/blob/maven-3.6.3/maven-model/src/main/java/org/apache/maven/model/merge/ ModelMerger.java # L2195) merges <resources> --In this implementation, <resource> is supposed to be merged in addition --But it's actually a subclass of this ModelMerger [MavenModelMerger](https://github.com/apache/maven/blob/maven-3.6.3/maven-model-builder/src/main/java/ org / apache / maven / model / merge / MavenModelMerger.java) seems to be merging --MavenModelMerger is [mergeBuildBase_Resources ()](https://github.com/apache/maven/blob/maven-3.6.3/maven-model-builder/src/main/java/org/apache/maven/model Overriding /merge/MavenModelMerger.java#L381) to merge the contents of the parent POM only if the <resources> of the target (child POM) is empty --In other words, if <resources> exists in the child POM, the merge will not be performed and only the contents of the child POM will be adopted (resulting in an overwrite operation). --Other than <resources>, do you have to take a look at this implementation of MavenModelMerger?

Check the POM after merging

--POMs have a parent-child relationship, and if you have multiple POMs as parents, you cannot tell the final state just by looking at the terminal POMs. —— Especially when the build doesn't work, you often want to make sure the POMs are merged as expected. --In such a case, you can use the effective-pom goal of maven-help-plugin.

effective-run the pom goal


> mvn help:effective-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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>example</groupId>
    <artifactId>parent</artifactId>
    <version>1.0.0</version>
  </parent>
  <groupId>example</groupId>
  <artifactId>child</artifactId>
  <version>1.0.0</version>
(Omitted because it is long)
...

--ʻEffective-pom` Goal prints the final POM with the information of all parent POMs including Super POM merged. ――By looking at this, you can see what the settings of the project are actually.

Merge configurations

--Description of plugin settings <configurations> The following does not have a fixed schema definition because the settings are different for each plugin. --Therefore, the merging of <configurations> is done uniformly according to certain rules. --For example, if <execution>, the definition is fixed so that it can be identified by <id>, so you can merge the same <id>. ――However, the tags under <configurations> cannot be identified in that way, so it feels like merging tags in the same position. -(I haven't confirmed the exact specifications and implementation, so I feel like that) ――Let's see how it is merged with an actual example

Parent POM


      ...
        <configuration>
          <persons>
            <person>
              <name>Taro</name>
              <age>18</age>
            </person>
            <person>
              <name>Hanako</name>
              <sex>female</sex>
            </person>
          </persons>
        </configuration>
      ...

Child POM


      ...
        <configuration>
          <persons>
            <person>
              <sex>male</sex>
            </person>
            <cat>nya-</cat>
            <person>
              <name>Ayako</name>
              <age>15</age>
            </person>
            <person>
              <name>Rin</name>
              <age>12</age>
              <sex>female</sex>
            </person>
          </persons>
        </configuration>
      ...

In this state, use help: effective-pom to check the merge result.

effective-pom


      ...
        <configuration>
          <persons>
            <person>
              <sex>male</sex>
              <name>Taro</name>
              <age>18</age>
            </person>
            <cat>nya-</cat>
            <person>
              <name>Ayako</name>
              <age>15</age>
              <sex>female</sex>
            </person>
            <person>
              <name>Rin</name>
              <age>12</age>
              <sex>female</sex>
            </person>
          </persons>
        </configuration>
      ...

――It's difficult to explain in words, but you can see that it has been merged in a nice way. ――Probably, if there is a tag with the same name in the same position, it seems that the contents are being merged recursively.

Control how to merge

――I feel that even the default behavior will merge reasonably well. --But if that's a problem, you can change the default merge behavior.

Parent POM


      ...
        <configuration>
          <persons>
            <person>
              <name>Taro</name>
              <age>18</age>
            </person>
            <person>
              <name>Hanako</name>
              <sex>female</sex>
            </person>
          </persons>
        </configuration>
      ...

--Parent POM has not changed

Child POM


      ...
        <configuration>
          <persons>
            <person combine.self="override">
              <sex>male</sex>
            </person>
            <cat>nya-</cat>
            <person combine.children="append">
              <name>Ayako</name>
              <age>15</age>
            </person>
            <person>
              <name>Rin</name>
              <age>12</age>
              <sex>female</sex>
            </person>
          </persons>
        </configuration>
      ...

--Adding the attributes combile.self =" override " and combine.children =" append "

effective-pom


      ...
        <configuration>
          <persons>
            <person combine.self="override">
              <sex>male</sex>
            </person>
            <cat>nya-</cat>
            <person combine.children="append">
              <name>Hanako</name>
              <sex>female</sex>
              <name>Ayako</name>
              <age>15</age>
            </person>
            <person>
              <name>Rin</name>
              <age>12</age>
              <sex>female</sex>
            </person>
          </persons>
        </configuration>
      ...

--You can see that the merged method has changed only for the element to which the combine. * Attribute has been added. --If you specify combine.self =" override ", the elements of the parent POM are completely discarded and only the elements of the child POM are used. --If combine.children =" append " is specified, the child POM element is simply added to the end of the parent POM element. --By using these two attributes in the child POM, you will be able to adjust the merging method to some extent. --However, these attributes are effective only for the element that describes this attribute. --Does not propagate to nested elements --If you want to change the behavior of nested elements, you need to specify the combine. * Attribute in the same way for nested elements.

Put together only the definitions in the parent project

--Parent project settings are always inherited by child projects --It is convenient if the settings are common to all child projects, but if the settings are required only for some child projects, extra inheritance will occur. --Therefore, there is a method to put only the definition in the parent project and explicitly apply it in the child project that wants to use the definition.

Summarize plugin definitions

Parent pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>parent</artifactId>
  <version>1.0.0</version>
  <packaging>pom</packaging>

  <build>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-antrun-plugin</artifactId>
          <version>1.8</version>
          <executions>
            <execution>
              <phase>validate</phase>
              <goals><goal>run</goal></goals>
              <configuration>
                <target>
                  <echo>Hello ${project.artifactId}</echo>
                </target>
              </configuration>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

--Use <pluginManagement> to put together plugin definitions in the parent project --Under this, you can write <plugins> just like a normal plugin definition. --However, what is described here only defines the settings and is not applied to the project.

Child 1 pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  <modelVersion>4.0.0</modelVersion>

  <parent>
    <groupId>example</groupId>
    <artifactId>parent</artifactId>
    <version>1.0.0</version>
  </parent>

  <artifactId>child1</artifactId>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>

--To actually apply to a project, describe <groupId>, <artifactId> in the plugin definition of the project you want to apply. --If the version is omitted, the one described in <pluginManagement> will be used. --It is also possible to add individual settings in the child project

Child 2 pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  <modelVersion>4.0.0</modelVersion>

  <parent>
    <groupId>example</groupId>
    <artifactId>parent</artifactId>
    <version>1.0.0</version>
  </parent>

  <artifactId>child2</artifactId>
</project>

――This is not applying any plugin in particular


Execution result (child 1)


> mvn validate
...
[INFO] ---------------------------< example:child1 >---------------------------
[INFO] Building child1 1.0.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-antrun-plugin:1.8:run (default) @ child1 ---
[INFO] Executing tasks

main:
     [echo] Hello child1
[INFO] Executed tasks
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
...

--The plugin is applied with the settings defined in the parent POM

Execution result (child 2)


> mvn validate
...
[INFO] ---------------------------< example:child2 >---------------------------
[INFO] Building child2 1.0.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
...

--No plugins applied

Summarize dependency definitions

Parent pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>parent</artifactId>
  <version>1.0.0</version>
  <packaging>pom</packaging>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.6</version>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.9</version>
    </dependency>
  </dependencies>
</project>

--Use <dependencyManagement> to group dependency definitions into a parent --Under this, you can write the same as normal <dependencies> --Similar to <pluginManagement>, the definition here is only a declaration, and it is applied to the project individually.

Child 1 pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  <modelVersion>4.0.0</modelVersion>

  <parent>
    <groupId>example</groupId>
    <artifactId>parent</artifactId>
    <version>1.0.0</version>
  </parent>

  <artifactId>child1</artifactId>

  <dependencies>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
    </dependency>
  </dependencies>
</project>

--Apply in child project by writing <groupId> and <artifactId> in the dependency. --If <version> is omitted, the one specified by <dependencyManagement> will be used. --It is also possible to overwrite <version> independently in the child project.

Child 2 pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  <modelVersion>4.0.0</modelVersion>

  <parent>
    <groupId>example</groupId>
    <artifactId>parent</artifactId>
    <version>1.0.0</version>
  </parent>

  <artifactId>child2</artifactId>
</project>

--This does not define any dependencies in particular


Execution result (effective of child 1-pom)


> mvn help:effective-pom
...
  <dependencies>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.6</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.9</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
...

--commons-io is applied in the version set in the parent POM

Execution result (effective of child 2)-pom)


> mvn help:effective-pom
...
  <dependencies>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.9</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
...

--commons-io dependencies not applied

Aggregation of projects

--The parent-child relationship was a form in which the child referred to the parent. ――On the other hand, in project aggregation, the parent refers to the child. --When you aggregate projects, you can specify goals and phases in the parent project and execute them.

Folder structure


|-pom.xml
`-sub/
  `-pom.xml

--Project whose top folder is the aggregation source --There is a project to be aggregated under the child folder

Aggregation source pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>root</artifactId>
  <version>1.0.0</version>
  <packaging>pom</packaging>

  <modules>
    <module>sub</module>
  </modules>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.8</version>
        <configuration>
          <target>
            <echo>Hello ${project.artifactId}</echo>
          </target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

--To aggregate projects, use <modules> in the project from which they are aggregated. --Under <modules>, list the projects to be aggregated with <module> --The <packaging> of the project to be aggregated must be pom.

Pom to be aggregated.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>sub</artifactId>
  <version>1.0.0</version>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.8</version>
        <configuration>
          <target>
            <echo>Hello ${project.artifactId}</echo>
          </target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

--Write pom.xml to be aggregated normally --Since this POM does not inherit the project of the aggregation source, the description of <groupId> etc. is individual.

Execution result (executed in the aggregation source project)


> mvn antrun:run
...
main:
     [echo] Hello sub
...
main:
     [echo] Hello root
...

--When the goal of the plug-in is executed in the project to be aggregated, the same goal is executed in the project to be aggregated. --In this way, when projects are aggregated, the commands executed in the aggregation source project will also be executed in the aggregation destination project. ――It is convenient to have this mechanism when you want to build all projects at once.

Combining aggregation and parent-child relationships

--The mechanism of aggregation and parent-child relationship can be combined (or rather, usually used in combination).

Folder structure


|-pom.xml
`-child/
  `-pom.xml

Parent pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>parent</artifactId>
  <version>1.0.0</version>
  <packaging>pom</packaging>

  <modules>
    <module>child</module>
  </modules>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.8</version>
        <configuration>
          <target>
            <echo>Hello ${project.artifactId}</echo>
          </target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

--There is no particular change in the composition of the parent POM

Child pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <parent>
    <groupId>example</groupId>
    <artifactId>parent</artifactId>
    <version>1.0.0</version>
  </parent>

  <artifactId>child</artifactId>
</project>

--Declare the parent project with <parent> --This allows the plugin settings to inherit the parent settings, eliminating the need for writing.

Execution result (executed in the parent project)


> mvn antrun:run
...
main:
     [echo] Hello parent
...
main:
     [echo] Hello child
...

--Parent-child relationship and aggregation can be applied at the same time

Java project build

-Understand how a project with packaging jar is built.

default Goals executed in the life cycle

--Packaging defaults to jar when creating a project that builds Java normally --Therefore, the goals executed in the default life cycle are: 1. resources:resources 2. compiler:compile 3. resources:testResources 4. compiler:testCompile 5. surefire:test 6. jar:jar 7. install:install 8. deploy:deploy ――Look at what each goal is doing one by one

Collect resources

--The first thing that runs is the [resources goal] of maven-resources-plugin (https://maven.apache.org/plugins/maven-resources-plugin/resources-mojo.html)

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>
</project>

--Verify with minimum configuration pom.xml

Folder structure


|-pom.xml
`-src/main/
  |-java/
  | `example/
  |  `-App.java
  `-resources/
    |-hoge.txt
    `-foo/
      `-bar.txt

--Files and folders are arranged appropriately under src / main / resources

Command execution


> mvn resources:resources
...
[INFO] --- maven-resources-plugin:2.6:resources (default-cli) @ hello ---
...
[INFO] BUILD SUCCESS

--resources: resources Execute goals directly

Folder structure after execution


|-pom.xml
|-src/main/
| |-java/
| | `example/
| |  `-App.java
| `-resources/
|   |-hoge.txt
|   `-foo/
|     `-bar.txt
`-target/classes/
  |-hoge.txt
  `-foo/
    `-bar.txt

--The following contents of src / main / resources are copied under the target / classes folder. --maven-resources-plugin provides the process of copying the project resource folder to the output folder --The resource folder and output folder are as follows by default. --Resource folder: src / main / resources --Output folder: target / classes --The resource folder is the folder set in $ {project.build.resources} --This value is set to $ {project.basedir} /src/main/resources in Super POM --The output destination folder is the location specified by the ʻoutputDirectory parameter of the resourcesgoal. --This parameter defaults to$ {project.build.outputDirectory} --And this value is set to$ {project.build.directory} / classesby default by Super POM --In addition,$ {project.basedir} / target is set in $ {project.build.directory} ` --So, for example, you can customize the behavior by writing pom.xml as follows.

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>

  <build>
    <resources>
      <resource>
        <directory>src/main/hoge</directory>
      </resource>
    </resources>
  </build>
</project>

--Changing the resource folder to src / main / hoge

Folder structure


|-pom.xml
`-src/main/
  |-hoge/
  | |-fizz.txt
  | `-hoge/
  |   `-fuga.txt
  |
  `-resources/
    |-buzz.txt
    `-foo/
      `-bar.txt

--There are two options, src / main / resources and src / main / hoge.

Execute resources goal


> mvn resources:resources
...

Execution result


|-pom.xml
|-src/main/
| |-hoge/
| | |-fizz.txt
| | `-hoge/
| |   `-fuga.txt
| |
| `-resources/
|   |-buzz.txt
|   `-foo/
|     `-bar.txt
|
`-target/classes/
  |-fizz.txt
  `-hoge/
    `-fuga.txt

--src / main / hoge It has changed so that only the following is copied


--In summary, the resources: resources goal works by default as follows: --Copy the files and folders under $ {project.basedir} /src/main/resources under $ {project.basedir} / target / classes --Resource folders can be set with <project> <build> <resources> --The output destination folder can be set with <project> <build> <outputDirectory>

Compile Java source

--The next goal to be executed is compile of maven-compiler-plugin. /plugins/maven-compiler-plugin/compile-mojo.html) Goal

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>
</project>

--Verify with the minimum configuration POM

Folder structure


|-pom.xml
`-src/main/java
  `-example/
    `-Hello.java

--Simple configuration with only Hello.java

Run compile goal


> mvn compiler:compile
...
[INFO] --- maven-compiler-plugin:3.1:compile (default-cli) @ hello ---
...
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR]Source option 5 is not currently supported. Please use 6 or later.
[ERROR]Target option 1.5 is not currently supported. 1.Please use 6 or later.

--Failed due to an error --Compile option [-source](https://docs.oracle.com/javase/jp/11/tools/javac.html#GUID-AEEC9F07-CB49-4E96-8BC7-BCC2C7F725C9__GUID-B4EE2436-E146- 428D-A3CB-E0DAE27BA5B7) and [-target](https://docs.oracle.com/javase/jp/11/tools/javac.html#GUID-AEEC9F07-CB49-4E96-8BC7-BCC2C7F725C9__GUID-89CBDEA1-9FF4- The error content is that the version specified in 4EA0-AB7D-B418FA2C3DE9) is too old with 5, 1.5. --In JDK 11, the versions below 5 for -source and -target are [cannot be specified](https://docs.oracle.com/javase/jp/11/migrate/index.html# JSMIG-GUID-77874D97-46F3-4DB5-85E4-2ACB5F8D760B) --If packaging is jar, the default version of maven-compiler-plugin is [3.1](https://maven.apache.org/ref/3.6.3/maven- core / default-bindings.html # Plugin_bindings_for_jar_packaging) --In 3.1 of maven-compiler-plugin, the version specification of -source and -target is [1.5] by default (https://github.com/apache/maven-compiler- plugin / blob / maven-compiler-plugin-3.1 /src/main/java/org/apache/maven/plugin/compiler/AbstractCompilerMojo.java#L120) --By the way, in 3.8.1 of the latest maven-compiler-plugin at the time of confirmation, [1.6](https://github.com/apache/maven-compiler-plugin/blob/maven-compiler-plugin-3.8. 1 / src / main / java / org / apache / maven / plugin / compiler / AbstractCompilerMojo.java # L100) is the default --So, to get rid of this error, you need to increase the version of maven-compiler-plugin or increase the specification of source and target. --It is safe to specify both to confirm the operation.

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>

  <properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
      </plugin>
    </plugins>
  </build>
</project>

--To specify source with maven-compiler-plugin, use source parameter Set --Although it can be specified with <configuration>, it can also be specified with the maven.compiler.source property. ――Here, the setting using the property is used (Is this more common?) --The same is true for target, which can be set with the maven.compiler.target property.

Execution result


> mvn compiler:compile
...
[INFO] --- maven-compiler-plugin:3.1:compile (default-cli) @ hello ---
...
[WARNING] File encoding has not been set, using platform encoding MS932, i.e. build is platform dependent!
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
...

--I was able to compile, but I got some warning --The warning is that the encoding of the source file depends on the environment defaults. --Specify the encoding of the source file in encoding parameter --As mentioned in the description, by default it uses $ {project.build.sourceEncoding} --However, this value is not set in Super POM, so it results in an environment default (such as MS932 for Windows). --So, let's set the encoding as well

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>

  <properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
      </plugin>
    </plugins>
  </build>
</project>

--From the description $ {project.build.sourceEncoding}, you can imagine that you should describe the element <sourceEncoding> under <project> <build>, but in reality, you declare the property ( Who knows </ del>) ――By the way, it is possible to set it with the property ʻencoding, but if you look it up on the net, the method of project.build.sourceEncoding will be caught. ――If it is ʻencoding, it may be applied to encodings other than Java source, or is there such a thing? (suitable)

Execution result


> mvn compiler:compile
...
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-cli) @ hello ---
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

--Successfully compiled without warning

Output result


|-pom.xml
|-src/main/java/
| :
`-target/
  |-classes/
  : `-example/
      `-Hello.class

--The compilation result is output under target / classes --The output destination setting is not described in the compile goal document. --This is the implementation class for the compile goal [outputDirectory](https://github.com/apache/maven-compiler-plugin/blob/maven-compiler-plugin-3.8.1/src/main/java /org/apache/maven/plugin/compiler/CompilerMojo.java#L76) Declared in the field --The default value is $ {project.build.outputDirectory} --Since readonly = true is set, this field cannot be set directly from the outside. --The source folder defaults to src / main / java --Also, there is no description in the document --In terms of implementation, [compileSourceRoots](https://github.com/apache/maven-compiler-plugin/blob/maven-compiler-plugin-3.8.1/src/main/java/org/apache/maven/plugin /compiler/CompilerMojo.java#L70) declared in the field --Looking at defaultValue, you can see that$ {project.compileSourceRoots}is set. --But when I try to reference this property called project.compileSourceRoots on pom.xml, I can't see the value. --compileSourceRoots is [MavenProject](https://github.com/apache/maven/blob/maven-3.6.3/maven-core/src/main/java/org/apache/maven/project/MavenProject.java # L131) Declared as a field in the class --This field is DefaultProjectBuilder The value is set by # L691) --From this implementation, you can see that project.build.sourceDirectory is set to compileSourceRoots. --And $ {project.basedir} /src/main/java is set in project.build.sourceDirectory by Super POM. ――If you look at this mechanism, you can expect that you cannot set multiple source folders. --If you want to set multiple source folders, you need to install a plugin called build-helper-maven-plugin.


--In summary, compiler: compile does the following: --Compile Java source code under $ {project.basedir} /src/main/java and output to $ {project.basedir} / target / classes --javac's -source, -target options can be specified with the maven.compiler.source, maven.compiler.target properties --Encoding can be specified with the project.build.sourceEncoding property --The source folder can be specified with <project> <build> <sourceDirectory> --If you want to specify multiple folders, you need build-helper-maven-plugin --The output destination folder is <project> <build> <outputDirectory>

Collecting and compiling resources for testing

--The next thing to run is resources: testResources, which collects resources for testing. Compile the source code for testing compiler: testCompile --The basic operation of each is the same as resources: resources, compiler: compile, so only roughly

Folder structure


|-pom.xml
`-src/test/
  |-java/
  | `-example/
  |   `-HelloTest.java
  |
  `-resources/
    |-foo/
    | `-bar.txt
    `-fizz.txt

--The test source code under src / test / java, Place test resource files under src / test / resources

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>

  <properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
      </plugin>
    </plugins>
  </build>
</project>

--pom.xml is the same as for compiler: compile

Run


> mvn resources:testResources compiler:testCompile
...
[INFO] --- maven-resources-plugin:2.6:testResources (default-cli) @ hello ---
...
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-cli) @ hello ---
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS

Execution result


|-pom.xml
|-src/test/
| :
`-target/
  `-test-classes/
    |-fizz.txt
    |-foo/
    | `-bar.txt
    `-example/
      `-HelloTest.class

--Results are output under target / test-classes


――When organized, the operation is as follows. --The testResources goal is to copy the files and folders under $ {project.basedir} /src/test/resources to $ {project.basedir} / target / test-classes. --Resource folders can be specified with <project> <build> <testResources> --The testCompile goal compiles the Java source files under $ {project.basedir} /src/test/java and outputs them to $ {project.basedir} / target / test-classes. --The source folder can be specified with <project> <build> <testSourceDirectory>

Run the test

--Next, in order to execute the compiled test code, [test goal](https: //) of maven-surefire-plugin maven.apache.org/surefire/maven-surefire-plugin/test-mojo.html) is executed.

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>

  <properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter</artifactId>
      <version>5.6.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.22.2</version>
      </plugin>
    </plugins>
  </build>
</project>

--The following modifications have been made to make JUnit5 work. --Add junit-jupiter to dependencies --Specify 2.22.2 for the version of maven-surefire-plugin --2.22.0 or higher must be specified to use JUnit5

Folder structure


|-pom.xml
`-src/
  |-main/java/
  | `-example/
  |   `-Hello.java
  `-test/java/
    `-example/
      `-HelloTest.java

--Place the test target class (Hello.java) and the test class (HelloTest.java)

Run


> mvn test
...
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello ---
...
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ hello ---
...
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hello ---
...
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ hello ---
...
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ hello ---
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running example.HelloTest
...
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.027 s - in example.HelloTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
...

> dir /b target\surefire-reports
example.HelloTest.txt
TEST-example.HelloTest.xml

--The surefire: test goal is tied to the test phase, so it is executed with the test phase specified. --It is possible to run surefire: test alone, but in that case the source must be compiled separately. --The test class to be executed is specified in includes parameter, and the following classes are executed by default. Is targeted - **/Test*.java - **/*Test.java - **/*Tests.java - **/*TestCase.java --Test results are printed in text and xml format under target / surefire-reports --This is specified in the surefire: test goal's reportsDirectory parameter (https://maven.apache.org/surefire/maven-surefire-plugin/test-mojo.html#reportsDirectory) (default is $ {project.build.directory} / surefire-reports)

Skip the test

--After the test phase, the package phase is executed, which jars the compilation result of the project. --That is, the test phase must complete successfully in order to generate the jar. --If the test fails in the test phase, the package phase will not run --It should be that the code that has not passed the test is not usable even if it is packed in a jar, but unfortunately there are projects where the test code is not maintained and the test does not pass. --In such cases, it is common (and should not be) to skip execution of the test phase and execute the package phase.

Execution result


> mvn -DskipTests package
...
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello ---
...
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ hello ---
...
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hello ---
...
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ hello ---
...
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ hello ---
[INFO] Tests are skipped.
...
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ hello ---
...

--surefire: test The goal has a parameter called skipTests. --If this is set, test execution will be skipped.


--To summarize, the test phase does the following: --Test code is executed by maven-surefire-plugin --In order to use JUnit 5, the version of maven-surefire-plugin must be 2.22.0 or higher. --The test class to be executed is specified in includes parameter. --Test results are printed under target / surefire-reports (reportsDirectory parameter" ) --Test execution can be skipped by setting the skipTests parameter --However, the use of this should be kept to the minimum necessary --The test is not maintained and you need a jar now (the correct response is to fix it so that the test passes) --The test passes, but it takes a long time to execute, so it cannot be executed every time. - etc

Harden in jar

--The process of solidifying the compilation result into a jar is the jar goal of maven-jar-plugin. .org / plugins / maven-jar-plugin / jar-mojo.html)

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>

  <properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
      </plugin>
    </plugins>
  </build>
</project>

--The minimum settings required for compilation

Folder structure


|-pom.xml
`-src/
  |-test/
  | :
  `-main/
    |-java/
    | `-example/
    |   `-Hello.java
    `-resources/
      `-hoge.txt

Run package phase


> mvn package
...
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello ---
...
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ hello ---
...
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hello ---
...
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ hello ---
...
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ hello ---
...
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ hello ---
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

--The jar: jar goal is tied to the package phase, so you are running the package phase.

Execution result


|-pom.xml
|-src/
| :
`-target/
  |-hello-1.0.0.jar
  :

--hello-1.0.0.jar is output directly under the target folder. --The output destination of the jar file is set by the outputDirectory parameter of the jar goal. --The default for this parameter is $ {project.build.directory} ($ {project.basedir} / target) --Also, the name of the jar file is finalName in the implementation of the jar goal. /org/apache/maven/plugins/jar/AbstractJarMojo.java#L80) declared in the field --This field is readonly = true, so it cannot be changed directly from the outside. --The value of this field is set to $ {project.build.finalName} --This value is set by Super POM to $ {project.artifactId}-$ {project.version} by default. --Therefore, if you want to rename the jar, you can set <project> <build> <finalName> --When you unzip this jar, the contents are as follows

text:hello-1.0.0.Contents of jar


|-hoge.txt
|-example/
| `-Hello.class
`-META-INF/
  |-MANIFEST.MF
  `-maven/example/hello/
    |-pom.properties
    `-pom.xml

--hoge.txt and Hello.class are packed with the output under target / classes by resources: resources and compiler: compile, respectively. --Which folder contents are packed in a jar is set by the classesDirectory parameter of the jar goal. Have been --The default for this parameter is $ {project.build.outputDirectory} ($ {project.basedir} / target / classes) --Pom.xml is output under META-INF, but the content is the same as pom.xml of this project. --MANIFEST.MF and pom.properties have the following contents, respectively.

MANIFEST.MF


Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven 3.6.3
Built-By: xxxxx
Build-Jdk: 11.0.6

pom.properties


#Generated by Maven
#Sun Mar 29 21:59:48 JST 2020
groupId=example
artifactId=hello
version=1.0.0

--These are set in the archive parameter of the jar goal. --Details of ʻarchive` settings can be found in Apache Maven Archiver – Reference. --These files are generated with the settings enabled by default


--In summary, the jar goal works like this:

  • file name
    • ${project.artifactId}-${project.version} --Specify with <project> <build> <finalName> to change --Output location
    • ${project.basedir}/target --Specify with <project> <build> <directory> to change --Packing target
    • ${project.basedir}/target/classes --If you want to change it, specify it with the <project> <build> <outputDirectory> or the classesDirectory parameter of the jar goal. --In addition, the ʻarchiveparameter can be used to set the information added underMANIFEST.MF and META-INF`.

Install in local repository

--ʻInstall` install goal of maven-install-plugin associated with the phase. apache.org/plugins/maven-install-plugin/install-mojo.html) provides the ability to install project artifacts in a local repository

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>
  ...
</project>

Run install


> mvn install
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
...

--ʻInstall: install The goal is tied to the ʻinstall phase, so you are running the ʻinstallphase (confusing) --When execution is complete, check inside the local repository --The default location of the local repository is% USERPROFILE% \ .m2 \ repository on Windows ( $ HOME / .m2 / repositoryon Linux OS) --If you have specified a different location insettings.xml`, that

Local repository


Local repository/
 |-example/
 : `-hello/
     |-1.0.0/
     : |-hello-1.0.0.jar
       :

--The jar file is stored in the local repository --The jar file to be registered is probably the jar file generated in the package phase --ʻInstall: installThe goal docs saidproject's main artifact, but I couldn't find a clear description of what would be project's main artifact. --In terms of implementation, [getArtifact () of MavenProject](https://github.com/apache/maven/blob/maven-3.6.3/maven-core/src/main/java/org/apache/maven/project [GetFile () of Artifact](https://github.com/apache/maven/blob/maven-3.6.3/maven-artifact/src/main/java/org/) which can be obtained by /MavenProject.java#L215) I could read up to the point where the file that can be obtained by apache / maven / artifact / Artifact.java # L85) seems to be installed, but I could not find the place where this File` object is set. --Artifs installed in the local repository will be visible in another local project

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>foo</artifactId>
  <version>1.0.0</version>

  <properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>example</groupId>
      <artifactId>hello</artifactId>
      <version>1.0.0</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
      </plugin>
    </plugins>
  </build>
</project>

--Declaring dependencies on hello-1.0.0.jar with<dependencies>

Foo.java


package example;

public class Foo {
    public static void main(String... args) {
        new Hello().hello();
    }
}

--I'm writing an implementation that uses the Hello class

Compile the project


> mvn compile
...
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ foo ---
...
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ foo ---
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
...

--Compiled successfully (Hello class has been resolved)


--In summary, the ʻinstallgoal works like this: --Probably install the artifacts generated in thepackage` phase (such as jar files) in your local repository --Installed artifacts will be visible as dependencies from other local projects

Deploy

--The last execution is the deploy phase --In the deploy phase, the deploy goal of maven-deploy-plugin plugins / maven-deploy-plugin / deploy-mojo.html) is executed --deploy goal is to deploy the project artifacts to a remote repository ―― I feel that there are few opportunities to actually use it even though it is troublesome to build the environment. </ Del> Verification is omitted.

Web project build

See how your project builds if you set -packaging to war --However, the plugins executed in the default phase are almost the same as in the case of jar. --The difference from jar is that the goal executed in the package phase is war war goal

Folder structure


|-pom.xml
`-src/main/
  |-java/
  | `-example/webapp/
  |   `-HelloServlet.java
  `-webapp/
    `-WEB-INF/
      `-hello.jsp

--Create a folder called src / main / webapp and under that a folder such as WEB-INF to include in war

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>webapp</artifactId>
  <version>1.0.0</version>
  <packaging>war</packaging>

  <properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.10</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.2.3</version>
      </plugin>
    </plugins>
  </build>
</project>

--war is specified for<packaging> --The following two are specified as dependencies - Servlet API - Apache Commons Lang3

Build


> mvn package
...
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ webapp ---
...
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ webapp ---
...
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ webapp ---
...
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ webapp ---
...
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ webapp ---
...
[INFO] --- maven-war-plugin:3.2.3:war (default-war) @ webapp ---
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

--As in the case of jar, the goal of the plugin is executed in each phase, and finally war: war is executed.

Output result


|-pom.xml
|-src/
| :
`-target/
  `-webapp-1.0.0.war

--The war file is generated directly under target --The output location is specified in the war goal's outputDirectory parameter and defaults to$ It is {project.build.directory} --The name of the war file is [warName](https://github.com/apache/maven-war-plugin/blob/maven-war-plugin-3.2.3/src/main/java/org/apache/ It is specified by a read-only parameter called maven / plugins / war / WarMojo.java # L71) and defaults to $ {project.build.finalName}. --The contents of webapp-1.0.0.war are as follows

text:webapp-1.0.0.The contents of the war


webapp-1.0.0.war/
|-WEB-INF/
| |-hello.jsp
| |-classes/
| | `-example/webapp/
| |   `-HelloServlet.class
| `-lib/
|   `-commons-lang3-3.10.jar
`-META-INF/
  |-MANIFEST.MF
  `-maven/example/webapp/
    |-pom.properties
    `-pom.xml

--You can see that the compilation result of src / main / java and the contents under src / main / webapp are contained in the war file. --Place files other than class files and library jars that you put in war under the src / main / webapp folder. --This is specified in the war goal's warSourceDirectory parameter and defaults to $ { basedir} / src / main / webapp --In addition, the Apache Commons Lang3 jar specified as a dependency is also stored under WEB-INF / lib. --The Servlet API jar is not stored --This is because the scope of the dependency on the Servlet API was specified in provided. --Detailed explanation of scope will be described later.


--In summary, if packaging is war, the project will be built as follows: --Basically built like jar --However, the point that the war: war goal is executed only in the package phase is different from the case of jar. --In the war: war goal, the compilation result of the project is output in a war file. --In addition to the class files, resources, and dependent libraries, the files placed under src / main / webapp are also stored in the war.

Run a Java application

Hello.java


package example;

import java.util.Arrays;

public class Hello {
    public static void main(String... args) {
        System.out.println("Hello World! args=" + Arrays.toString(args));
    }
}

--Hello World, implementation that outputs command line arguments

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>

  <properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>1.6.0</version>
        <executions>
          <execution>
            <id>default-cli</id>
            <configuration>
              <mainClass>example.Hello</mainClass>
              <arguments>
                <argument>one</argument>
                <argument>two</argument>
                <argument>three</argument>
              </arguments>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

-A plugin called exec-maven-plugin has been added.

Run


> mvn compile exec:java
...
[INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ hello ---
Hello World! args=[one, two, three]
...

--Hello.java was executed --If you use the [java goal] of ʻexec-maven-plugin (https://www.mojohaus.org/exec-maven-plugin/java-mojo.html), you can put the build result of the project in the classpath. Can execute Java programs --ʻExec-maven-plugin also has an exec goal that allows you to execute arbitrary commands. Omitted here --mainClass You can execute Java program by specifying Main class with parameter. -arguments You can pass command line arguments with parameters --You can also pass arguments with the parameter commandlineArgs, but this is for use when executing from the command line described below (probably).

Run from command line

--For the first example, it is necessary to describe all the execution configurations in pom.xml in advance. --In some cases, you may want to execute it while changing various arguments on the command line. --In that case, it is easier to specify the goal parameters via the system properties.

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <build>
    <plugins>
      ...
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>1.6.0</version>
        <executions>
          <execution>
            <id>default-cli</id>
            <configuration>
              <mainClass>example.Hello</mainClass>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

--Since it is troublesome to specify the Main class from the command line, I think that only this can be described in pom.xml in advance.

Execution result


> mvn compile exec:java -Dexec.args="ONE TWO THREE"
...
Hello World! args=[ONE, TWO, THREE]

-commandlineArgs You can use the parameter to specify the argument as a space-separated string. --When specifying in system properties, specify in ʻexec.args`

Dependencies

Dependency scope

--You can set a dependency called ** Scope **. --Scope represents the range in which the dependency is used. --For example, the dependency specified in the compile scope indicates that it will always be used from the time the source code is compiled to the time the application is executed. --Also, the dependency with the test scope indicates that it should be used only when compiling the test code (src / test / java) and executing the test. --There are 6 types of scopes as follows. - compile - provided - runtime - test - system - import

compile scope

pom.xml


<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-lang3</artifactId>
  <version>3.10</version>
</dependency>

--If no scope is specified, the compile scope is adopted by default (it can be specified). --The compile scope indicates that you always need that dependency from compilation to execution.

provided scope

pom.xml


<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>4.0.1</version>
  <scope>provided</scope>
</dependency>

--The provided scope indicates that the dependency is provided by the execution environment. --Use when the following conditions are met --Required for compilation and testing --However, the execution environment provides the jar at runtime, so the application does not need to keep it separately. --The most common example is the Servlet API. --The Servlet API uses the one provided by the application server that deploys the war, so the application does not need to have a separate dependency at run time. --For the same reason, specify other APIs (EJB, JAX-RS, etc ...) provided by Java EE (Jakarta EE) with provided. --When a war is generated with maven-war-plugin, the dependencies specified in provided are not placed under WEB-INF / lib.

runtime scope

pom.xml


<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.2.12</version>
    <scope>runtime</scope>
</dependency>

--The runtime scope is the opposite of provided and is used with dependencies that are not needed at compile time but are needed at run time. --A typical example is the JDBC driver. --When writing a program using the JDBC driver, the implementation provides java.sql.Connection provided by the standard API. You only have to rely on classes such as sql / java / sql / Connection.html) --Basically, it does not directly depend on the concrete classes provided by each database product. ――But, of course, you need an entity at runtime --So, this applies to the case where it is not needed at compile time but needed at runtime.

test scope

pom.xml


<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.6.1</version>
    <scope>test</scope>
</dependency>

--test scope is used for dependencies that are used only when compiling and running the test source. --Cannot be used when compiling or running the main source code --Use with dependencies that are only needed for testing, such as JUnit

system scope

pom.xml


<dependency>
  <groupId>javax.sql</groupId>
  <artifactId>jdbc-stdext</artifactId>
  <version>2.0</version>
  <scope>system</scope>
  <systemPath>${java.home}/lib/rt.jar</systemPath>
</dependency>

--The system scope indicates that the dependency is provided by the system (JRE or JDK of the execution environment). --This scope seems to be prepared for the purpose of using extension libraries that are not in the repository and are stored internally by the JRE and JDK. --If you specify the system scope, you must specify the path of the target jar file with<systemPath>. --You can also have a library in your project that doesn't exist in the repository and use it to reference it. ――Originally, it is a straightforward approach to prepare a private repository and manage it there. --For the time being, the use of this scope is deprecated. - System Dependencies

import scope

Folder structure


|-foo/
| `-pom.xml
`-bar/
  `-pom.xml

--There are two projects, foo and bar

pom.xml(foo)


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>foo</artifactId>
  <version>1.0.0</version>
  <packaging>pom</packaging>

  <dependencyManagement>
    <dependencies>
      <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-lang3</artifactId>
          <version>3.10</version>
      </dependency>
      <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-text</artifactId>
          <version>1.8</version>
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>

--The foo project sets packaging to pom and declares only<dependencyManagement> --The following two are declared as dependent targets. - org.apache.commons:commons-lang3:3.10 - org.apache.commons:commons-text:1.8

pom.xml(bar)


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>bar</artifactId>
  <version>1.0.0</version>

  <dependencyManagement>
    <dependencies>
      <dependency>
          <groupId>example</groupId>
          <artifactId>foo</artifactId>
          <version>1.0.0</version>
          <type>pom</type>
          <scope>import</scope>
      </dependency>
      <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-lang3</artifactId>
          <version>3.9</version>
      </dependency>
      <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-csv</artifactId>
          <version>1.8</version>
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>

--In the bar project, in <dependencyManagement>, the foo project mentioned earlier is specified in the ʻimport scope. --ʻImport Scope can only be specified in <dependencyManagement> --ʻImportIf you specify the scope, you must also specify the pom </ type>. --In addition, the following two are declared as other dependent targets. - org.apache.commons:commons-lang3:3.9 -org.apache.commons:commons-csv:1.8 --In this state, check ʻeffective-pom of the bar project.

effective-Confirmation of pom(bar)


> cd bar

> mvn help:effective-pom
...
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.9</version>
      </dependency>
      <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-csv</artifactId>
        <version>1.8</version>
      </dependency>
      <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-text</artifactId>
        <version>1.8</version>
      </dependency>
    </dependencies>
  </dependencyManagement>
artifactId foo bar effective-pom
commons-lang3 3.10 3.9 3.9
commons-csv - 1.8 1.8
commons-text 1.8 - 1.8

--The declaration of dependency on the foo project has disappeared, and instead the dependencies declared in <dependencyManagement> of the foo project have been added. --However, if the artifacts are duplicated, the version of the bar project is adopted (commons-lang3). --As you can see, ʻimport has a special scope to import (import) `of other pom projects.

BOM --There is a method called ** BOM (bill of materials) ** that uses the ʻimport scope as a version control method for dependencies in multiple projects. --In BOM, first prepare a BOM project with pom.xml -- is declared in the pom.xml of the BOM project, which defines the dependencies used in each project. --For each project, load this BOM project with ʻimport scope --Dependency versions are declared in the BOM project, so each project only needs to declare groupId, ʻartifactId in `. --This allows the BOM project to centrally manage the version of the dependency used in all projects. --By the way, the BOM of Spring Boot is [here](https://repo1.maven.org/maven2/org/springframework/boot/spring-boot-dependencies/2.2.6.RELEASE/spring-boot-dependencies-2.2. 6.RELEASE.pom) --By loading this BOM, you can match the version of the library you use to the one supported by Spring Boot.


--In order to give a bird's-eye view of the range of each scope, I made a table of the relationship between scopes and goals (excluded because ʻimport` is special).

maven.jpg

-- indicates that the goal refers to and uses the dependency of the corresponding scope. --For war: war, it means whether it will be packed in the generated war file. --Other than that, it means whether or not it is set in the classpath.

Check the dependencies in the tree

--You can check the dependency of the project by displaying it in a tree structure graph.

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
  </dependencies>
</project>

--Declaring Spring Framework web and jdbc as dependencies ――However, the library that the project depends on is not limited to this, and in fact it also depends on the library that spring-web and spring-jdbc depend on. --You can't tell just by looking at pom.xml how many libraries your project ultimately depends on. -tree goal of maven-dependency-plugin If you execute plugin / tree-mojo.html), you can see all the dependencies including this transitional dependency in the tree structure graph.

Execution result


> mvn dependency:tree
...
[INFO] +- org.springframework:spring-web:jar:5.2.5.RELEASE:compile
[INFO] |  +- org.springframework:spring-beans:jar:5.2.5.RELEASE:compile
[INFO] |  \- org.springframework:spring-core:jar:5.2.5.RELEASE:compile
[INFO] |     \- org.springframework:spring-jcl:jar:5.2.5.RELEASE:compile
[INFO] \- org.springframework:spring-jdbc:jar:5.2.5.RELEASE:compile
[INFO]    \- org.springframework:spring-tx:jar:5.2.5.RELEASE:compile
...

--You can see that spring-web further depends on spring-beans, spring-core, and spring-core depends on spring-jcl. --And you can see that spring-jdbc depends on spring-tx --By the way, spring-jdbc also depends on spring-beans and spring-core, but the display is omitted because it overlaps with the spring-web side. --By default, the dependencies of all scopes are output, but you can also narrow down by scope parameter. it can

Collect dependency jars

--In rare cases, you want to get all the actual jar files that your project depends on. --This can be achieved with the copy-dependencies goal of maven-dependency-plugin. -Try running with the same settings as pom.xml in ↑

Execution result


> mvn dependency:copy-dependencies
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
...

> dir /b target\dependency
spring-beans-5.2.5.RELEASE.jar
spring-core-5.2.5.RELEASE.jar
spring-jcl-5.2.5.RELEASE.jar
spring-jdbc-5.2.5.RELEASE.jar
spring-tx-5.2.5.RELEASE.jar
spring-web-5.2.5.RELEASE.jar

--All dependent jars are output under the target / dependency folder --By default, jars of all scopes are targeted, but narrow down by includeScope parameter etc. be able to

Profile

--Basically, it is good to build the project so that the same result is output with the same settings in every environment. ――The build succeeds in one environment, but an error occurs in another environment, which is troublesome. ――However, it seems that it is rare that environment-dependent build settings are required during actual development (although I don't know). --If you want to switch the contents of pom.xml depending on the build environment (enable a specific plugin or change the setting value), you can use a mechanism called ** Profile **.

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>

  <profiles>
    <profile>
      <id>foo</id>

      <properties>
        <message>foo profile!!</message>
      </properties>

      <dependencies>
        <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-lang3</artifactId>
          <version>3.10</version>
        </dependency>
      </dependencies>

      <build>
        <directory>${project.basedir}/build</directory>
      </build>
    </profile>
  </profiles>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.8</version>
        <configuration>
          <target>
            <echo>message = ${message}</echo>
            <echo>project.build.directory = ${project.build.directory}</echo>
            <echo>dependency[0] = ${project.dependencies[0].artifactId}</echo>
          </target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

--<profiles> <profile> declares a profile called foo --In the foo profile, properties, dependencies, and project.build.directory settings are set. --I use maven-antrun-plugin to display those values

Execution result


> mvn antrun:run
...
     [echo] message = ${message}
     [echo] project.build.directory = F:\tmp\maven\hello\target
     [echo] dependency[0] = ${project.dependencies[0].artifactId}
...

> mvn -P foo antrun:run
...
     [echo] message = foo profile!!
     [echo] project.build.directory = F:\tmp\maven\hello\build
     [echo] dependency[0] = commons-lang3

--When executed normally, the contents set in the foo profile are not reflected. --On the other hand, if you specify -P foo and execute it, you can see that the contents set in the foo profile are reflected. --In this way, using a profile allows you to define settings that apply only when you use that profile. --Profile definition is described by <profile> --<id> to set a name to uniquely identify the profile --Other than that, you can basically describe the elements that can be described in pom.xml (<dependencies>, <build>, etc.) as they are. --To specify the profile, specify -P followed by<id>of the profile on the command line.

Specify multiple profiles and execute

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <profiles>
    <profile>
      <id>foo</id>
      <properties>
        <foo>FOO</foo>
        <message>foo profile!!</message>
      </properties>
    </profile>
    <profile>
      <id>bar</id>
      <properties>
        <bar>BAR</bar>
        <message>bar profile!!</message>
      </properties>
    </profile>
  </profiles>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>1.8</version>
        <configuration>
          <target>
            <echo>foo = ${foo}</echo>
            <echo>bar = ${bar}</echo>
            <echo>message = ${message}</echo>
          </target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

--Declaring two profiles, foo and bar --message is declared in both profiles to be duplicated

Execution result


> mvn -P bar,foo antrun:run
...
     [echo] foo = FOO
     [echo] bar = BAR
     [echo] message = bar profile!!

--When specifying multiple profiles, list ʻid`s separated by commas. --Duplicate elements seem to be adopted later on pom.xml (it does not seem to be in the order specified in the profile)

Enable profile by default

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <profiles>
    <profile>
      <id>foo</id>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <properties>
        <message>foo profile!!</message>
      </properties>
    </profile>
    <profile>
      <id>bar</id>
      <properties>
        <message>bar profile!!</message>
      </properties>
    </profile>
  </profiles>

  <build>
    <plugins>
      <plugin>
        ...
        <configuration>
          <target>
            <echo>message = ${message}</echo>
          </target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

--The foo profile is set to<activeByDefault> true </ activeByDefault>

Execution result


> mvn antrun:run
...
     [echo] message = foo profile!!
...

> mvn -P bar antrun:run
...
     [echo] message = bar profile!!

--The foo property is enabled by default --If you set <activation> <activeByDefault> to true, the profile will be enabled by default. --If a different profile is specified with -P, the profile with<activeByDefault>is true will be invalid.

Enable profile only when conditions are met

Enable system properties if declared

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <profiles>
    <profile>
      <id>foo</id>
      <activation>
        <property>
          <name>foo</name>
        </property>
      </activation>
      <properties>
        <message>foo profile!!</message>
      </properties>
    </profile>
  </profiles>

  <build>
    <plugins>
      <plugin>
        ...
        <configuration>
          <target>
            <echo>message = ${message}</echo>
          </target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

--Declaring <property> in <activation>

Execution result


> mvn antrun:run
...
     [echo] message = ${message}
...

> mvn -Dfoo antrun:run
...
     [echo] message = foo profile!!

--The profile is not specified by -P, but the foo profile is enabled by declaring the system property with -Dfoo. --In <activation>, you can define the conditions to enable the profile. --<property> can be specified on the condition that a system property is declared or a specific value is set. --Here, only <name> foo </ name> is set, so if the system property foo is set, the profile will be valid regardless of the value. --If the value is also a condition, declare <value> as follows:

When the value of the system property is also included in the condition


        <property>
          <name>foo</name>
          <value>enable</value>
        </property>

Execution result


> mvn -Dfoo antrun:run
...
     [echo] message = ${message}
...

> mvn mvn -Dfoo=enable antrun:run
...
     [echo] message = foo profile!!

--The foo profile is enabled only when the value of the system property foo is ʻenable`.

Conditional to JDK version

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <profiles>
    <profile>
      <id>jdk11</id>
      <activation>
        <jdk>11</jdk>
      </activation>
      <properties>
        <message>jdk11 profile!!</message>
      </properties>
    </profile>
    <profile>
      <id>jdk14</id>
      <activation>
        <jdk>14</jdk>
      </activation>
      <properties>
        <message>jdk14 profile!!</message>
      </properties>
    </profile>
  </profiles>

  <build>
    <plugins>
      <plugin>
        ...
        <configuration>
          <target>
            <echo>message = ${message}</echo>
          </target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

--You are using the <jdk> element in <activation>

Execution result


> java --version
openjdk 11.0.6 2020-01-14
...

> mvn antrun:run
...
     [echo] message = jdk11 profile!!
...

> java --version
openjdk 14 2020-03-17
...

> mvn antrun:run
...
     [echo] message = jdk14 profile!!

--The profile has been switched according to the version of the JDK at runtime. --You can use <jdk> to make the Java version at runtime a condition for profile application. --The condition described in <jdk> is prefix-matched and compared with the Java version. --If you specify 11, it also matches 11.0.6 because it is a prefix match. --Furthermore, you can write a range specification such as (, 11] (in this case, it matches 11 or lower versions). --Refer to Apache Maven Enforcer Built-In Rules – Version Range Specification for how to write the range specification. --For the Java version to be compared, the value obtained by the system property java.version is used. --Implementation is probably [this](https://github.com/apache/maven/blob/maven-3.6.3/maven-model-builder/src/main/java/org/apache/maven/model/profile/ activation / JdkVersionProfileActivator.java # L66) --You can negate the condition by prefixing it with !, Like <jdk>! 11 </ jdk>.

Condition the OS

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <profiles>
    <profile>
      <id>Windows</id>
      <activation>
        <os>
          <name>Windows 10</name>
        </os>
      </activation>
      <properties>
        <message>Windows profile!!</message>
      </properties>
    </profile>
    <profile>
      <id>Linux</id>
      <activation>
        <os>
          <name>Linux</name>
        </os>
      </activation>
      <properties>
        <message>Linux profile!!</message>
      </properties>
    </profile>
  </profiles>

  <build>
    <plugins>
      <plugin>
        ...
        <configuration>
          <target>
            <echo>message = ${message}</echo>
          </target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

--<activation> is set to <os>

Execution result(Windows)


> mvn antrun:run
...
     [echo] message = Windows profile!!

Execution result(Linux)


> mvn antrun:run
...
     [echo] message = Linux profile!!

--The applied profile is switched depending on the OS at runtime. --<os> allows the OS to be used as a condition for profile application at run time --<name> is conditional on the name of the OS --The OS name uses the value that can be obtained from the system property ʻos.name. --It seems that there is no distinction between uppercase and lowercase letters. --In addition to the name, you can specify the following conditions - --OS type --See [Apache Maven Enforcer Built-In Rules – Require OS Version](https://maven.apache.org/enforcer/enforcer-rules/requireOS.html) for a list of possible values. --By the way, for Linux, specify ʻunix. - <arch> --CPU architecture --Specify x86 or ʻamd64 -` --OS version --If you specify multiple of these conditions, they will all be combined with the AND condition. --The value of the current environment can be found in [display-info goal](http: /) of maven-enforcer-plugin. You can check by executing /maven.apache.org/enforcer/maven-enforcer-plugin/display-info-mojo.html)

Execution result


> mvn enforcer:display-info
...
[INFO] Maven Version: 3.6.3
[INFO] JDK Version: 11.0.6 normalized as: 11.0.6
[INFO] OS Info: Arch: amd64 Family: windows Name: windows 10 Version: 10.0

The existence of the file is a condition

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <profiles>
    <profile>
      <id>Exists</id>
      <activation>
        <file>
          <exists>${basedir}/pom.xml</exists>
        </file>
      </activation>
      <properties>
        <message>Exists profile!!</message>
      </properties>
    </profile>
  </profiles>

  <build>
    <plugins>
      <plugin>
        ...
        <configuration>
          <target>
            <echo>message = ${message}</echo>
          </target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

--<activation> specifies <file>

Execution result


> mvn antrun:run
...
     [echo] message = Exists profile!!

--You can use <file> to use the presence or absence of a file as a condition for applying a profile. --<exists> is set on condition that the file exists --Use <missing> if the condition is that the file does not exist --In the file path specification, the embedded parameter is $ {basedir} or system property / request property? There is a limitation that it can only be used --If you write $ {project.basedir} /pom.xml, it will not be judged well.

Check available profiles

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <profiles>
    <profile>
      <id>foo</id>
      <properties>
        <message>foo profile!!</message>
      </properties>
    </profile>
    <profile>
      <id>bar</id>
      <properties>
        <message>bar profile!!</message>
      </properties>
    </profile>
  </profiles>

  ...
</project>

--foo, bar, two profiles are defined

Execution result


> mvn help:all-profiles
...
[INFO] Listing Profiles for Project: example:hello:jar:1.0.0
  Profile Id: bar (Active: false , Source: pom)
  Profile Id: foo (Active: false , Source: pom)

-all-profiles in maven-help-plugin You can check the available profiles by running -plugin / all-profiles-mojo.html)

Check active profile

Execution result


> mvn -P foo help:active-profiles antrun:run
...
Active Profiles for Project 'example:hello:jar:1.0.0':

The following profiles are active:

 - foo (source: example:hello:1.0.0)
...
     [echo] message = foo profile!!

--Use active-profiles to see which profiles are active at runtime it can --Maybe it's useful for debugging

When to use profile

--Profiles allow you to create different build results for each profile ――For this reason, if the profiles are too diverse, different developers may get different build results. --There was a rule like "For development use, you have to enable the develop profile "and forgot to specify it. --Changes in build results can cause confusion --As you can imagine from the fact that conditions such as <os> can be set, I think the original purpose of the profile is to absorb the differences in the build environment. ――Therefore, I think it is better to avoid using it for other purposes as much as possible (personal opinion). --For example, the profile may not be used in the method of switching the configuration file used for development, verification environment, and production environment. --I feel that it is best practice to use environment variables as a way to switch app settings for each environment these days. --Reference: III. Settings | The Twelve-Factor App (Japanese translation)

Make your own plugin

--You can make your own plugin --If the plugins at ʻorg.apache.maven.pluginsorcom.codehaus.mojo` do not meet your goals, you will have to create your own plugins.

Hello World

pom.xml


<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>example</groupId>
  <artifactId>hello-maven-plugin</artifactId>
  <version>1.0.0</version>
  <packaging>maven-plugin</packaging>

  <properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-plugin-api</artifactId>
      <version>3.6.3</version>
    </dependency>

    <dependency>
      <groupId>org.apache.maven.plugin-tools</groupId>
      <artifactId>maven-plugin-annotations</artifactId>
      <version>3.6.0</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-plugin-plugin</artifactId>
        <version>3.6.0</version>
      </plugin>
    </plugins>
  </build>
</project>

--Set packaging to maven-plugin --Set the following two as dependencies - org.apache.maven:maven-plugin-api - org.apache.maven.plugin-tools:maven-plugin-annotations --This is specified in the provided scope --Setting maven-plugin-plugin --When you try to compile with Java 11, it seems that you will get an error unless you update the version of this plugin?

HelloMojo.java


package example;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;

@Mojo(name="hello")
public class HelloMojo extends AbstractMojo {

    public void execute() throws MojoExecutionException {
        getLog().info("Hello Custom Plugin!");
    }
}

--ʻAbstractMojoCreate a class by inheriting the class --ThisHelloPluginclass corresponds to one goal --Implement the processing of the plugin in the ʻexecute ()method --The goal meta information is set with the @Mojo annotation. --name becomes the name of the goal

Build


> mvn install
...

――Run the ʻinstall` phase to install the created plugin in your local repository --Try using the installed plugin in another project

pom.xml(Other projects)


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>

  <build>
    <plugins>
      <plugin>
        <groupId>example</groupId>
        <artifactId>hello-maven-plugin</artifactId>
        <version>1.0.0</version>
      </plugin>
    </plugins>
  </build>
</project>

--You have set hello-maven-plugin to<plugin>

Execution result


> mvn hello:hello
...
[INFO] Hello Custom Plugin!

--I was able to execute my own plug-in

Plugin name (artifactId)

pom.xml


...
  <groupId>example</groupId>
  <artifactId>hello-maven-plugin</artifactId>
  <version>1.0.0</version>
...

--It is customary to set ʻartifactId of your own plug-in to XXX-maven-plugin. --If you set ʻartifactId to this pattern, the meta definition will be automatically created with the XXX part as the prefix of the plugin. --Trial, check inside the created jar file

Contents of jar


hello-1.0.0.jar/
 |-example/
 `-META-INF/
   |-MANIFEST.MF
   `-maven/
     |-example/
     `-plugin.xml

--Looking at the contents of this plugin.xml, it looks like this:

plugin.xml


...
<plugin>
  <name>hello-maven-plugin</name>
  <description></description>
  <groupId>example</groupId>
  <artifactId>hello-maven-plugin</artifactId>
  <version>1.0.0</version>
  <goalPrefix>hello</goalPrefix>
  <isolatedRealm>false</isolatedRealm>
  <inheritedByDefault>true</inheritedByDefault>
...

--<goalPrefix> is now hello --This allows this plugin to be prefixed with hello: <goal>. --If you have ʻartifactId called foo-maven-plugin, the prefix is foo`.

Mojo --The class that implements the goal of Maven plugin is called ** Mojo (Maven Old Java Object) **. --When reading Maven documentation, the term Mojo appears here and there. ――In that case, you can think of it as a class that implements goals.

Define parameters

HelloMojo.java


package example;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

@Mojo(name="hello")
public class HelloMojo extends AbstractMojo {
    @Parameter
    private String message;

    public void execute() throws MojoExecutionException {
        getLog().info("message = " + message);
    }
}

--Adding a message field to Mojo and annotating it with @Parameter --Getter and Setter are not defined

pom.xml(Another project)


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <build>
    <plugins>
      <plugin>
        <groupId>example</groupId>
        <artifactId>hello-maven-plugin</artifactId>
        <version>1.0.0</version>
        <configuration>
          <message>Hello World!!</message>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

--<configuration> declares the same element as the Mojo field name

Execution result


> mvn hello:hello
...
[INFO] message = Hello World!!

--The message field declared in Mojo can now be specified as a parameter. --By the way, in this state, you cannot specify the value in the system property.

Allow parameters to be specified in system properties

HelloMojo.java


package example;
...

@Mojo(name="hello")
public class HelloMojo extends AbstractMojo {
    @Parameter(property="hello.message")
    private String message;

    public void execute() throws MojoExecutionException {
        getLog().info("message = " + message);
    }
}

--Set property of @Parameter to the name specified in the system properties.

pom.xml (separate project)


...
      <plugin>
        <groupId>example</groupId>
        <artifactId>hello-maven-plugin</artifactId>
        <version>1.0.0</version>
      </plugin>
...

--Do not specify <configuration> (if it is set, this will take precedence)

Execution result


> mvn hello:hello -Dhello.message="HELLO WORLD!!"
...
[INFO] message = HELLO WORLD!!

--You can now set the value via system properties

Set default values for parameters

HelloMojo.java


package example;
...

@Mojo(name="hello")
public class HelloMojo extends AbstractMojo {
    @Parameter(property="hello.message", defaultValue="Hello Custom Plugin!!")
    private String message;

    public void execute() throws MojoExecutionException {
        getLog().info("message = " + message);
    }
}

--You can declare the default value for that parameter with the @Parameter annotation defaultValue.

pom.xml(Another project)


...
      <plugin>
        <groupId>example</groupId>
        <artifactId>hello-maven-plugin</artifactId>
        <version>1.0.0</version>
      </plugin>
...

--<configuration> is unconfigured

Execution result


> mvn hello:hello
...
[INFO] message = Hello Custom Plugin!!
...

> mvn hello:hello -Dhello.message=OVERRIDE!!
...
[INFO] message = OVERRIDE!!

--If nothing is set, you can see that the value set in defaultValue is adopted.

Use an expression for the default value

HelloMojo.java


package example;
...

@Mojo(name="hello")
public class HelloMojo extends AbstractMojo {
    @Parameter(defaultValue="${hello.mojo.message}")
    private String message;

    public void execute() throws MojoExecutionException {
        getLog().info("message = " + message);
    }
}

--For the value of defaultValue, you can write an expression like$ {...} --Refer to PluginParameterExpressionEvaluator Javadoc for the values that can be referenced in the expression. --You can also refer to system properties and project properties (<properties>)

pom.xml(Another project)


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <properties>
    <hello.mojo.message>Project Property</hello.mojo.message>
  </properties>

  <build>
    <plugins>
      <plugin>
        <groupId>example</groupId>
        <artifactId>hello-maven-plugin</artifactId>
        <version>1.0.0</version>
      </plugin>
    </plugins>  
  </build>
</project>

--Declaring a value in <properties> with the same key that was declared in the expression defaultValue

Execution result


> mvn hello:hello
...
[INFO] message = Project Property
...

> mvn hello:hello -Dhello.mojo.message="System Property"
...
[INFO] message = System Property

--The value declared in <properties> is set in the messge parameter --Can also be overridden with system properties

Types that can be used for parameters

--Parameter types can be declared with various types, not just String

HelloMojo.java


package example;

import java.io.File;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

@Mojo(name="hello")
public class HelloMojo extends AbstractMojo {
    @Parameter
    private int intValue;
    @Parameter
    private long longValue;
    @Parameter
    private boolean booleanValue;
    @Parameter
    private double doubleValue;
    @Parameter
    private Date dateValue;
    @Parameter
    private File fileValue;
    @Parameter
    private URL urlValue;
    @Parameter
    private HelloEnum enumValue;
    @Parameter
    private List<String> listValues;
    @Parameter
    private Map<String, String> mapValue;

    public void execute() throws MojoExecutionException {
        Log log = getLog();
        log.info("intValue=" + intValue);
        log.info("longValue=" + longValue);
        log.info("booleanValue=" + booleanValue);
        log.info("doubleValue=" + doubleValue);
        log.info("dateValue=" + dateValue);
        log.info("fileValue=" + fileValue);
        log.info("urlValue=" + urlValue);
        log.info("enumValue=" + enumValue);
        log.info("listValues=" + listValues);
        log.info("mapValue=" + mapValue);
    }

    public enum HelloEnum {
        HELLO,
        WORLD;
    }
}

--Parameters are defined with various types

pom.xml(Another project)


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <build>
    <plugins>
      <plugin>
        <groupId>example</groupId>
        <artifactId>hello-maven-plugin</artifactId>
        <version>1.0.0</version>
        <configuration>
          <intValue>123</intValue>
          <longValue>1234567890</longValue>
          <booleanValue>true</booleanValue>
          <doubleValue>1234.5678</doubleValue>
          <dateValue>2019-10-20 12:13:14</dateValue>
          <fileValue>foo/bar</fileValue>
          <urlValue>https://www.google.co.jp/</urlValue>
          <enumValue>HELLO</enumValue>
          <listValues>
            <aaa>fizz</aaa>
            <bbb>buzz</bbb>
          </listValues>
          <mapValue>
            <foo>FOO</foo>
            <bar>BAR</bar>
          </mapValue>
        </configuration>
      </plugin>
    </plugins>  
  </build>
</project>

Execution result


> mvn hello:hello
...
[INFO] intValue=123
[INFO] longValue=1234567890
[INFO] booleanValue=true
[INFO] doubleValue=1234.5678
[INFO] dateValue=Sun Oct 20 12:13:14 JST 2019
[INFO] fileValue=F:\tmp\maven\hello\foo\bar
[INFO] urlValue=https://www.google.co.jp/
[INFO] enumValue=HELLO
[INFO] listValues=[fizz, buzz]
[INFO] mapValue={bar=BAR, foo=FOO}
...

--Primitive types such as ʻint, long, float, double, boolean can be used normally --Wrapper class is also possible --java.util.Date is specified in one of the following formats --yyyy-MM-dd HH: mm: ss.S a (Example: 2005-10-06 2:22: 55.1 PM) --yyyy-MM-dd HH: mm: ssa (Example: 2005-10-06 2:22:55 PM) ――However, even if they do not match exactly, they can be analyzed flexibly (AM and PM can be omitted, but the time cannot be omitted). --java.io.File treats the value as a path --java.net.URLtreats the value as a URL --In case of enum type, it can be set by specifying the same value as the listed constant. --In the case ofList, if you enumerate the elements with arbitrary names while writing the same element as the parameter name, it seems that it will be processed as an element of List. --Usually, it's easier to write like ... --In the case ofMap, the name of the nested element is the key and the value of the element is the value. --Although verification is omitted, java.util.Properties` can be used in the same way.

Associate the default phase

HelloMojo.java


package example;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;

@Mojo(name="hello", defaultPhase=LifecyclePhase.VALIDATE)
public class HelloMojo extends AbstractMojo {

    public void execute() throws MojoExecutionException {
        getLog().info("Hello Mojo!!");
    }
}

--You can specify the default phase with defaultPhase of @ Mojo --Use the LifecyclePhase enumeration to specify the phase --Here, it is linked to the validate phase.

pom.xml(Another project)


...
      <plugin>
        <groupId>example</groupId>
        <artifactId>hello-maven-plugin</artifactId>
        <version>1.0.0</version>
        <executions>
          <execution>
            <goals>
              <goal>hello</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
...

--hello Only the goal is declared, and the phases are not linked.

Execution result(Another project)


> mvn validate
...
[INFO] Hello Mojo!!

--The hello goal is being executed in the execution of the validate phase.

Delete the product

Folder structure


|-pom.xml
`-target/

pom.xml


<?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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hello</artifactId>
  <version>1.0.0</version>
</project>

Execution result


> mvn clean
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ hello ---
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

Folder structure (after execution)


`-pom.xml

-clean goal of maven-clean-plugin You can remove all project products by running plugin / clean-mojo.html) --The clean phase is specified here. --The clean goal is associated with the clean phase by default (confusing) --By default, the following folders are targeted for deletion - ${project.build.directory} - ${project.build.outputDirectory} - ${project.build.testOutputDirectory} - ${project.reporting.outputDirectory} --$ {project.basedir} / target will be deleted unless you have changed the path of the above folder.

Add the folder to be deleted

Folder structure


|-pom.xml
|-target/
`-foo/

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project ...>
  ...

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-clean-plugin</artifactId>
        <version>3.1.0</version>
        <configuration>
          <filesets>
            <fileset>
              <directory>${project.basedir}/foo</directory>
            </fileset>
          </filesets>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

--Adding <filesets> and adding the foo folder to be deleted

Execution result


> mvn clean
...
[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ hello ---
[INFO] Deleting ...\foo (includes = [], excludes = [])
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

Folder structure (after execution)


`-pom.xml

--Not only target but foo has been deleted --filesets parameter allows you to add folders and files to be deleted --<filesets> specifies a collection of Fileset To do --It seems that you can narrow down the files not only with <directory> but also with <includes> and <excludes> (I haven't tried it).

Reference and official document table of contents

It's too difficult to understand where and what information is, so I'll sort it out </ del>